home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / libs / intoids.lha / Intoids 1.0 / Source / Intoids.c next >
Text File  |  1997-02-12  |  160KB  |  5,119 lines

  1. /****** intoids.library/--background-- **************************************
  2. *
  3. *   NAME
  4. *       intoids.library -- Arbitrary precision integer math in 32 bits.
  5. *
  6. *   FUNCTION
  7. *       This set of subroutines lets other programs easily handle large
  8. *       integer numbers.  It is a wrapper around the GNU Integer library
  9. *       (which implements large integers as an array of shorts) that lets you
  10. *       deal with all integers as 32 bit values (small integers are stored as
  11. *       a shifted odd value and larger ones are stored as a pointer to a
  12. *       variation of the GNU large integer).  It also supports special values
  13. *       for infinity and not-a-number conditions.  Written to support large
  14. *       sized files in the upcoming AGMS virtual file system.
  15. *
  16. *   INPUTS
  17. *       RecycleMe - most functions that return an Intoid also take a
  18. *           parameter called RecycleMe.  Treat it as if it is used in a call
  19. *           to the FreeIntoid function.  If RecycleMe isn't NULL then its
  20. *           storage will be recycled to hold the result (or reallocated if it
  21. *           is too small).  If RecycleMe is NULL then new memory will be
  22. *           allocated for the function result.  If the function fails
  23. *           (returns NULL) then the RecycleMe variable is deallocated.  This
  24. *           is here mostly to reduce the number of memory allocations that
  25. *           would otherwise be made.
  26. *
  27. *   RESULT
  28. *       Intoid values - all functions returning Intoids will return NULL if
  29. *           out of memory or if the number is too big to be represented.
  30. *           Some also return NULL for not-a-number error conditions (like
  31. *           divide by zero).
  32. *
  33. *   COPYRIGHT
  34. *       Modifications for storing smaller integers in 32 bit values and
  35. *       conversion to an Amiga library copyright (C) 1996 by Alexander G. M.
  36. *       Smith.  Original long integer code copyright (C) 1988 Free Software
  37. *       Foundation.
  38. *
  39. *       This library is free software; you can redistribute it and/or modify
  40. *       it under the terms of the GNU Library General Public License as
  41. *       published by the Free Software Foundation; either version 2 of the
  42. *       License, or (at your option) any later version.
  43. *
  44. *       This library is distributed in the hope that it will be useful, but
  45. *       WITHOUT ANY WARRANTY; without even the implied warranty of
  46. *       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  47. *       Library General Public License for more details.
  48. *
  49. *       You should have received a copy of the GNU Library General Public
  50. *       License along with this library; if not, write to the Free Software
  51. *       Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  52. *
  53. *   AUTHOR
  54. *       Modifications for the Amiga library and 32 bit storage implemented by
  55. *       Alexander G. M. Smith, Ottawa Canada, agmsmith@achilles.net,
  56. *       agmsmith@FreeNet.Carleton.ca, agmsmith@bix.com,
  57. *       71330.3173@compuserve.com, and probably other places in the future.
  58. *       Send mail to all these addresses to find ones which are still valid
  59. *       (list made in November 1996).
  60. *
  61. *       Original long integer code written by Doug Lea (dl@rocky.oswego.edu).
  62. *       The GNU G++ library's Integer.cc file also has these attributions:
  63. *       Some of the following algorithms are very loosely based on those from
  64. *       MIT C-Scheme bignum.c, which is
  65. *           Copyright (c) 1987 Massachusetts Institute of Technology
  66. *       with other guidance from Knuth, vol. 2
  67. *       Thanks to the creators of the algorithms.
  68. *
  69. *   NOTES
  70. *       To compile intoids.library, use the SAS C compiler, version 6.56.
  71. *       Use 32 bit integers, 32 bit longs and 16 bit shorts.  Naturally, you
  72. *       can use whatever compiler you want to write code for calling the
  73. *       library (SASC and GNU are supported, and there is an .FD file for
  74. *       making interfaces for other compilers).  Here's the SCOPTIONS file I
  75. *       used for making intoids.library:
  76. *           PARAMETERS=REGISTERS
  77. *           NOSTACKCHECK
  78. *           NOCHECKABORT
  79. *           ERRORREXX
  80. *           OPTIMIZE
  81. *           LINK
  82. *           LISTMACROS
  83. *           LISTINCLUDES
  84. *           STRINGSCONST
  85. *           OPTIMIZERINLINELOCAL
  86. *           VERBOSE
  87. *           MAP
  88. *           MAPHUNK
  89. *           MAPSYMBOLS
  90. *           MAPLIB
  91. *           MAPXREFERENCE
  92. *           STRICT
  93. *           LIBRARYCODE
  94. *           OPTIMIZERTIME
  95. *           STRINGSECTION=CODE
  96. *           STARTUP=libinit
  97. *           PROGRAMNAME=intoids.library
  98. *           MAPFILE=Intoids.map
  99. *           PUBSCREEN=Workbench
  100. *           LIBRARYFDFILE=Intoids.fd
  101. *           LIBRARYVERSION=1
  102. *           LIBRARYREVISION=0
  103. *           OPTIMIZERCOMPLEXITY=1
  104. *           OPTIMIZERDEPTH=1
  105. *           OPTIMIZERRECURDEPTH=0
  106. *
  107. *   BUGS
  108. *       Not all the functions from the GNU Integer library were implemented.
  109. *       If you want modulo, power and other functions, either ask me or do it
  110. *       yourself.  It's a matter of cutting and pasting the code from GNU's
  111. *       Integer.cc and fixing up a few things to handle Intoids rather than
  112. *       IntReps.
  113. *
  114. *   SEE ALSO
  115. *       GNU's G++ library Integer.cc file for the original code and yet more
  116. *       arbitrary precision functions.
  117. *
  118. *****************************************************************************
  119. * $Header: Big:Programming/C/Intoids/Library/RCS/Intoids.c,v 1.28 1997/02/12 17:35:04 AGMS Exp $
  120. *
  121. * $Log: Intoids.c,v $
  122. * Revision 1.28  1997/02/12  17:35:04  AGMS
  123. * Enable custom version string.
  124. *
  125. * Revision 1.27  1997/02/12  17:31:43  AGMS
  126. * Changed some titles for better autodoc index.
  127. *
  128. * Revision 1.26  1997/02/12  16:45:08  AGMS
  129. * Added AGMS Portable Integer Format stuff.
  130. *
  131. * Revision 1.25  1997/01/21  17:50:25  AGMS
  132. * Added autodocs for new AGMS Portable Integer functions.
  133. *
  134. * Revision 1.24  1997/01/14  17:12:42  AGMS
  135. * Added AutoDoc comments for all the exported functions.  Realised
  136. * that there are no portable binary number formats...
  137. *
  138. * Revision 1.23  1997/01/14  12:39:26  AGMS
  139. * Started adding AutoDoc comments.
  140. *
  141. * Revision 1.22  1997/01/12  17:57:15  AGMS
  142. * Fixed a memory leak with multiplying two small integers with a
  143. * result that didn't fit in a long.  Also added more parameter
  144. * error checking.
  145. *
  146. * Revision 1.21  1997/01/12  12:31:53  AGMS
  147. * Changed to fit in with the standard Amiga C compiler include
  148. * directory structure.  Also uses standard Amiga type names
  149. * (STRPTR instead of char *).  Unfortunately that loses the
  150. * const declarations for some of the arguments.
  151. *
  152. * Revision 1.20  1996/12/29  09:27:58  AGMS
  153. * *** empty log message ***
  154. *
  155. * Revision 1.19  1996/12/29  09:05:02  AGMS
  156. * Dropped in division functions from the GNU library.
  157. *
  158. * Revision 1.18  1996/12/28  13:36:21  AGMS
  159. * Added remaining multiplication code and some utility functions.
  160. *
  161. * Revision 1.17  1996/12/18  16:40:48  AGMS
  162. * Added functions for negating and comparing Intoids, fixed some bugs.
  163. *
  164. * Revision 1.16  1996/12/12  19:26:36  AGMS
  165. * Found getreg function, can call the utility.library long division
  166. * routines directly and get both the division result and the remainder.
  167. *
  168. * Revision 1.15  1996/12/12  18:22:48  AGMS
  169. * Adding a long to an IntRep and Multiplying an IntRep by a
  170. * long now work.
  171. *
  172. * Revision 1.14  1996/12/09  16:55:34  AGMS
  173. * Now use SHORT_PER_LONG and do other things to make it work
  174. * even for longs that aren't 32 bits (but probably some things
  175. * still aren't ready for 64 bit longs).  Multiplication also
  176. * under construction.
  177. *
  178. * Revision 1.13  1996/12/08  17:22:23  AGMS
  179. * Addition seems to work, now for multiplication!
  180. *
  181. * Revision 1.12  1996/12/08  15:22:15  AGMS
  182. * Addition functions typed in, ready for testing.
  183. *
  184. * Revision 1.11  1996/12/07  17:06:43  AGMS
  185. * Converted to use less indirection.
  186. *
  187. * Revision 1.10  1996/12/07  14:17:21  AGMS
  188. * Oops, just realised that you don't need the extra level of
  189. * indirection in Intoids, can point at the IntRep directly,
  190. * not at a pointer to the IntRep.
  191. *
  192. * Revision 1.9  1996/12/04  17:01:31  AGMS
  193. * Changed some inline functions to be macros for better optimization.
  194. * ResizeIntoid now leaves old value alone if requested.
  195. * Added functions for normalizing and copying Intoids.
  196. * Addition function under construction.
  197. *
  198. * Revision 1.8  1996/12/03  16:17:42  AGMS
  199. * Now with even more international support.  Uses Utility.library for
  200. * 32 bit math (division with remainder mostly).
  201. *
  202. * Revision 1.7  1996/11/28  16:04:41  AGMS
  203. * Typed in stuff needed for printing an Intoid.
  204. *
  205. * Revision 1.6  1996/11/23  17:22:49  AGMS
  206. * Now compiles and operates as a library, still no guts.
  207. *
  208. * Revision 1.5  1996/11/21  16:37:30  AGMS
  209. * Not much.
  210. *
  211. * Revision 1.4  1996/11/21  16:16:00  AGMS
  212. * Now compiles, but doesn't have any guts yet.
  213. *
  214. * Revision 1.3  1996/11/18  17:25:09  AGMS
  215. * Documentation changes.
  216. *
  217. * Revision 1.2  1996/11/14  18:00:40  AGMS
  218. * Added GNU license header info.
  219. *
  220. * Revision 1.1  1996/11/14  15:50:03  AGMS
  221. * Initial revision
  222. */
  223.  
  224.  
  225. #define __USE_SYSBASE 1
  226.   /* Need this to make the exec.library headers use the library base global
  227.   variable SysBase in SAS C (otherwise it just uses location $4 which slows
  228.   things down because it is in CHIP memory). */
  229.  
  230. #include <limits.h>   /* For CHAR_BIT definition. */
  231. #include <string.h>   /* For string reverse function. */
  232. #include <dos.h>      /* For getreg builtin function. */
  233. #include <proto/exec.h>
  234. #include <exec/memory.h>
  235. #include <exec/libraries.h>
  236. #include <proto/intuition.h>
  237. #include <proto/locale.h>
  238. #include <proto/utility.h>
  239. #include <utility/utility.h>
  240. #include <libraries/Intoids.h> /* Get datatypes, no function prototypes. */
  241.  
  242. #if __SASC
  243.   /* Special register assignment keywords (parameters passed in registers,
  244.   not on the stack) for making the library, SAS/C Amiga dialect. */
  245.  
  246.   #define REGA0 register __a0
  247.   #define REGA1 register __a1
  248.   #define REGA6 register __a6
  249.   #define REGD0 register __d0
  250.   #define REGD1 register __d1
  251.  
  252.   /* Declare the function as requiring a reload of the global data
  253.   pointer and as using register arguments. */
  254.  
  255.   #define LIBFUNC __saveds __asm
  256.  
  257. #else /* Some other compiler. */
  258.   #define REGA0
  259.   #define REGA1
  260.   #define REGA6
  261.   #define REGD0
  262.   #define REGD1
  263.   #define LIBFUNC
  264. #endif
  265.  
  266.  
  267. /* Because the debugger doesn't recognize static functions in shared
  268.    libraries, disable the "static" function declaration when doing
  269.    debugging.  Of course, it doesn't really matter since most code
  270.    can link with the shared library code only through the exported
  271.    interface (which uses only functions identified as LIBFUNC).
  272.    The exception is the library startup code. */
  273.  
  274. #if _DEBUG
  275.   #define LOCALFUNC
  276. #else /* Normal use. */
  277.   #define LOCALFUNC static
  278. #endif
  279.  
  280. /* AutoRequestor values for the body text, similar to AUTOFRONTPEN and
  281.    other default values. */
  282.  
  283. #define BODYLEFTEDGE    6
  284. #define BODYTOPEDGE     5
  285.  
  286.  
  287. /*
  288.  Sizes of shifts for multiple-precision arithmetic.
  289.  These should not be changed unless Integer representation
  290.  as unsigned shorts is changed in the implementation files.
  291.  
  292.  Also, some other stuff has been hard coded to use shorts,
  293.  like the macros that strip off the I_SHIFT bits from a
  294.  long integer.
  295. */
  296.  
  297. #define I_SHIFT         (sizeof(short) * CHAR_BIT)
  298. #define I_RADIX         ((unsigned long)(1L << I_SHIFT))
  299. #define I_MAXNUM        ((unsigned long)((I_RADIX - 1)))
  300. #define I_MINNUM        ((unsigned long)(I_RADIX >> 1))
  301. #define I_POSITIVE      1
  302. #define I_NEGATIVE      0
  303.  
  304. /* All routines assume SHORT_PER_LONG > 1 */
  305. #define SHORT_PER_LONG  ((unsigned)(((sizeof(long) + sizeof(short) - 1) / sizeof(short))))
  306. #define CHAR_PER_LONG   ((unsigned)sizeof(long))
  307.  
  308. /*
  309.   minimum and maximum sizes for an IntRep (number of shorts in the IntRep
  310.   number storage array).
  311. */
  312.  
  313. #define MINIntRep_SIZE   4
  314. #define MAXIntRep_SIZE   I_MAXNUM
  315.  
  316.  
  317.  
  318. typedef struct IntRepStruct
  319. {
  320.   unsigned short  currentLength;    /* Number of entries in numberArray. */
  321.   BOOL            positiveSign;     /* 1 means >= 0; 0 means < 0. */
  322.   unsigned short  allocatedLength;  /* 0 means constant.  Number of shorts. */
  323.   unsigned short  numberArray [1];  /* least significant value in [0]. */
  324. } IntRep, *IntRepPointer;
  325.   /* Large integer representation, essentially the same as in the GNU G++
  326.   Integer library.  The numberArray (and thus the total record size) grows as
  327.   needed.  Unused entries in numberArray always contain zero (an algorithm
  328.   invariant), so that it is easier to grow into them.  The allocatedLength is
  329.   the number of shorts in numberArray.  Zero allocatedLength means that the
  330.   number is a special constant value that should not be freed (allocated as a
  331.   global variable, not dynamically allocated).  This special constant feature
  332.   isn't used because Intoids can represent special small integers (like 0 and
  333.   +-1) efficiently. */
  334.  
  335.  
  336. /* Copied from Intoids.h for easier reference: */
  337. /* typedef void * Intoid; */
  338.   /* As far as the user sees it, it is an opaque type.  Treat it like
  339.   a pointer to a dynamically allocated object, though it sometimes
  340.   isn't and sometimes is.  A NULL (zero) value Intoid means that an error
  341.   happened (out of memory, divide by zero, etc) [...]  Besides storing really
  342.   big numbers and not-a-number, the Intoids can also represent positive and
  343.   negative infinity. */
  344.  
  345. typedef IntRepPointer  IntoidAsPointer;
  346. typedef signed long    IntoidAsLong;
  347.   /* Intoid encoding: values that are a multiple of 4 are a pointer to an
  348.   IntRep.  Odd values are a small integer value shifted left by two, with the
  349.   low bit set (arithmatic shift right by 1 bit to get the integer).  Other
  350.   special codes are drawn from values generated by 2 + 4 * n: positive
  351.   infinity as 6, negative infinity as 10, see IntoidSpecialCodes for more
  352.   details. */
  353.  
  354.  
  355. typedef enum IntoidSpecialCodesEnum
  356. {
  357.   ISC_NOT_A_NUMBER = 0,
  358.   ISC_POSITIVE_INFINITY,
  359.   ISC_NEGATIVE_INFINITY,
  360.   ISC_MAX
  361. } IntoidSpecialCodes;
  362.   /* The various special codes, used for non-integer numbers like infinity or
  363.   not-a-number (which is used here as the NULL pointer of numbers).  In the
  364.   actual 32 bit Intoid, the value used is 2 + 4 * IntoidSpecialCode.  The
  365.   exception is the Intoid of all zero which also corresponds to
  366.   ISC_NOT_A_NUMBER too.  Precomputed for INTOID_POSITIVE_INFINITY and
  367.   INTOID_NEGATIVE_INFINITY. */
  368.  
  369.  
  370.  
  371. /******************************************************************************
  372.  * G L O B A L   C O N S T A N T   D A T A
  373.  *
  374.  * This stuff gets allocated in the code segment (static const declarations).
  375.  * Since this is a library, it would be wastefully in both code and data
  376.  * segments if we asked for the data segment (all hunks get loaded then the
  377.  * data ones get copied to the separately allocated library base record).
  378.  */
  379.  
  380. #if 1 /* bleeble */
  381. const char __far _LibID [] = "intoids 1.0 " __AMIGADATE__
  382. " (by AGMSmith) ($Id: Intoids.c,v 1.28 1997/02/12 17:35:04 AGMS Exp $)\r\n";
  383.   /* Library version string used in the ROMTag, similar to the VER: full
  384.   version string (if the ROMTag exists, it's string is used by the AmigaDOS
  385.   version command instead of the VER: string).  Overrides a string defined by
  386.   the linker, which just says "Version 1.0", this causes a link time error
  387.   (but it still links anyways). */
  388. #endif
  389.  
  390.  
  391.  
  392. static const char CreditsMessage [] =  /* static const for code segment. */
  393. "$VER: intoids 1.0 " __AMIGADATE__ " ($Id: Intoids.c,v 1.28 1997/02/12 17:35:04 AGMS Exp $)\n"
  394. "\n"
  395. "Intoids.library - An Amiga runtime shared code library for efficiently\n"
  396. "handling large and small integer values using pointer sized data fields.\n"
  397. "\n"
  398. "Modifications for storing smaller integers in 32 bit values and conversion\n"
  399. "to an Amiga library copyright © 1996 by Alexander G. M. Smith.\n"
  400. "Original long integer code copyright © 1988 Free Software Foundation.\n"
  401. "\n"
  402. "This library is free software; you can redistribute it and/or\n"
  403. "modify it under the terms of the GNU Library General Public\n"
  404. "License as published by the Free Software Foundation; either\n"
  405. "version 2 of the License, or (at your option) any later version.\n"
  406. "\n"
  407. "This library is distributed in the hope that it will be useful,\n"
  408. "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
  409. "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
  410. "Library General Public License for more details.\n"
  411. "\n"
  412. "You should have received a copy of the GNU Library General Public\n"
  413. "License along with this library; if not, write to the Free\n"
  414. "Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
  415. "\n"
  416. "Modifications for the Amiga library and 32 bit storage implemented by\n"
  417. "Alexander G. M. Smith, Ottawa Canada, agmsmith@achilles.net,\n"
  418. "agmsmith@FreeNet.Carleton.ca, agmsmith@bix.com, 71330.3173@compuserve.com,\n"
  419. "and probably other places in the future.  Send mail to all these addresses\n"
  420. "to find ones which are still valid (list made in November 1996).\n"
  421. "\n"
  422. "Original long integer code written by Doug Lea (dl@rocky.oswego.edu).\n"
  423. "The GNU G++ library's Integer.cc file also has these attributions:\n"
  424. "  Some of the following algorithms are very loosely based on those from\n"
  425. "  MIT C-Scheme bignum.c, which is\n"
  426. "      Copyright (c) 1987 Massachusetts Institute of Technology\n"
  427. "  with other guidance from Knuth, vol. 2\n"
  428. "  Thanks to the creators of the algorithms.\n";
  429.  
  430.  
  431.  
  432. static const char * const DefaultErrorStrings [MSG_INTOIDS_MAX] =
  433. {
  434.   /* MSG_INTOIDS_NOT_A_NUMBER */            "not-a-number",
  435.   /* MSG_INTOIDS_INFINITY */                "infinity",
  436.   /* MSG_INTOIDS_NUMBER_TOO_BIG_TO_PRINT */ "(too big to print)",
  437.   /* MSG_INTOIDS_PRINTING_OUT_OF_MEMORY */  "(out of memory)",
  438.   /* MSG_INTOIDS_NEW_TOO_BIG */             "Attempt to create a number bigger than the maximum allowed size.",
  439.   /* MSG_INTOIDS_INTREP_OUT_OF_MEMORY */    "Out of memory for allocating Intoid data bits.",
  440.   /* MSG_INTOIDS_CREDITS */                 CreditsMessage,
  441.   /* MSG_INTOIDS_CONTINUE_SHOWING_ERRORS */ "Continue showing intoids.library error messages?",
  442.   /* MSG_INTOIDS_BAD_INPUT_PARMS */         "Bad function input parameters.",
  443.   /* MSG_INTOIDS_DIVIDE_BY_ZERO */          "Divide by zero.",
  444.   /* MSG_INTOIDS_PI_READ_ERROR */           "Error while reading portable integer data.",
  445.   /* MSG_INTOIDS_PI_WRITE_ERROR */          "Error while writing portable integer data.",
  446.   /* MSG_INTOIDS_PI_SEEK_ERROR */           "Error while seeking in portable integer data.",
  447.   /* MSG_INTOIDS_PI_BAD_FORMAT */           "Portable integer has unusual format, bad data?",
  448.   /* MSG_INTOIDS_UNKNOWN_MESSAGE */         "Unknown error message number used!"
  449. };
  450.   /* English version of localizable strings used by GetIntoidsMessage.  See
  451.   the IntoidStringNumbers typedef for the numbers. */
  452.  
  453.  
  454.  
  455. /******************************************************************************
  456.  * Things too large to be on the stack or that are global.  These are put into
  457.  * the library base record and accessed via a dedicated register, thus a
  458.  * maximum of 32K of global near data.  Mostly alphabetical order.
  459.  */
  460.  
  461. struct IntuitionBase *IntuitionBase;
  462. struct Library *LocaleBase;
  463. struct Library *UtilityBase;
  464. struct ExecBase *SysBase;
  465.   /* Various library base global variables.  NULL if the library isn't open,
  466.   our custom startup/exit code opens them and closes them. */
  467.  
  468.  
  469. struct Catalog *CurrentCatalog;
  470.   /* Used for finding language dependent string messages.  NULL if not
  471.   available.  Read about locale.library for details. */
  472.  
  473.  
  474. struct Locale *CurrentLocale;
  475.   /* Identifies the current default locale from locale.library.  NULL
  476.   if none available (use our own isspace() etc instead). */
  477.  
  478.  
  479. BOOL DisplayErrors = TRUE;
  480.   /* TRUE if we are showing error messages, FALSE if the user has canceled
  481.   error message displays (remains FALSE until the library gets flushed from
  482.   memory). */
  483.  
  484.  
  485. const char *ErrorMessagePntr = CreditsMessage;
  486.   /* Points to the current error message.  If no error,
  487.   points to the credits string. */
  488.  
  489.  
  490.  
  491. /****** intoids.library/GetIntoidsMessage ***********************************
  492. *
  493. *   NAME
  494. *       GetIntoidsMessage -- Convert a message number to a localised string.
  495. *
  496. *   SYNOPSIS
  497. *       YourString = GetIntoidsMessage( StringNumber )
  498. *       D0                            D0
  499. *
  500. *       STRPTR GetIntoidsMessage( IntoidStringNumbers );
  501. *
  502. *   FUNCTION
  503. *       Returns a pointer to a message which corresponds to the string
  504. *       number, the particular string depends on the user's language
  505. *       preferences.  The string is obtained from the Intoids.catalog
  506. *       file if the user's language isn't English.
  507. *
  508. *   INPUTS
  509. *       StringNumber - an enum from 0 to MSG_INTOIDS_MAX-1 that identifies
  510. *           the message you want the international string for.  If you ask
  511. *           for a string that doesn't exist, you will get the string
  512. *           for MSG_INTOIDS_UNKNOWN_MESSAGE.
  513. *
  514. *   RESULT
  515. *       YourString - a pointer to a read-only string which will be valid
  516. *           for as long as intoids.library is open.
  517. *
  518. *   SEE ALSO
  519. *       locale.library - docs on how locale stuff works.
  520. *       Intoids.h - the enum of all message numbers.
  521. *
  522. *****************************************************************************
  523. */
  524.  
  525. STRPTR LIBFUNC GetIntoidsMessage (REGD0 IntoidStringNumbers StringNumber)
  526. {
  527.   STRPTR ReturnValue;
  528.  
  529.   if (StringNumber < 0 || StringNumber >= MSG_INTOIDS_MAX)
  530.     StringNumber = MSG_INTOIDS_UNKNOWN_MESSAGE;
  531.  
  532.   ReturnValue = (STRPTR) (DefaultErrorStrings [StringNumber]);
  533.  
  534.   if (CurrentCatalog != NULL)
  535.     ReturnValue = GetCatalogStr (CurrentCatalog,
  536.     (long) StringNumber, ReturnValue);
  537.  
  538.   return ReturnValue;
  539. }
  540.  
  541.  
  542.  
  543. /******************************************************************************
  544.  * Our runtime error message display function.  If the user hits Cancel, no
  545.  * more messages will be displayed until the library is flushed from memory.
  546.  */
  547.  
  548. void LOCALFUNC DisplayErrorMessage (const char *ErrorMessage)
  549. {
  550.   struct IntuiText CancelIText =
  551.   {
  552.     AUTOFRONTPEN,
  553.     AUTOBACKPEN,
  554.     AUTODRAWMODE,
  555.     AUTOLEFTEDGE,
  556.     AUTOTOPEDGE,
  557.     AUTOITEXTFONT,
  558.     NULL, /* Message string goes here */
  559.     AUTONEXTTEXT
  560.   };
  561.   struct IntuiText ErrorIText = CancelIText;
  562.   struct IntuiText ExplainingIText = CancelIText;
  563.   struct IntuiText OKIText = CancelIText;
  564.   BOOL OKHit;
  565.  
  566.   if (DisplayErrors)
  567.   {
  568.     ErrorIText.LeftEdge = BODYLEFTEDGE;
  569.     ErrorIText.TopEdge = BODYTOPEDGE;
  570.     ErrorIText.IText = (UBYTE *) ErrorMessage;
  571.     ErrorIText.NextText = &ExplainingIText;
  572.  
  573.     ExplainingIText.LeftEdge = BODYLEFTEDGE;
  574.     ExplainingIText.TopEdge = BODYTOPEDGE + 12;
  575.     ExplainingIText.IText = (STRPTR)
  576.     GetIntoidsMessage (MSG_INTOIDS_CONTINUE_SHOWING_ERRORS);
  577.     ExplainingIText.NextText = NULL;
  578.  
  579.     if (CurrentLocale != NULL)
  580.     {
  581.       CancelIText.IText = GetLocaleStr (CurrentLocale, NOSTR);
  582.       OKIText.IText = GetLocaleStr (CurrentLocale, YESSTR);
  583.     }
  584.     else
  585.     {
  586.       CancelIText.IText = (STRPTR) "Cancel";
  587.       OKIText.IText = (STRPTR) "OK";
  588.     }
  589.  
  590.     OKHit = AutoRequest (NULL /* No parent window */,
  591.     &ErrorIText, &OKIText, &CancelIText,
  592.     0, 0, 512 /* width */, 80 /* height */);
  593.  
  594.     if (!OKHit) /* Cancel selected.  Stop showing errors. */
  595.       DisplayErrors = FALSE;
  596.   }
  597.   ErrorMessagePntr = ErrorMessage;
  598. }
  599.  
  600.  
  601.  
  602. /****** intoids.library/SmallIntToIntoid ************************************
  603. *
  604. *   NAME
  605. *       SmallIntToIntoid -- Macro to convert a small value int to an Intoid.
  606. *
  607. *   SYNOPSIS
  608. *       MyIntoid = SmallIntToIntoid( ANumber )
  609. *
  610. *       Intoid SmallIntToIntoid( int );
  611. *
  612. *   FUNCTION
  613. *       Converts a short integer or char (unsigned or signed) to an Intoid.
  614. *       Will also work for long integers if they aren't larger than
  615. *       0x3FFFFFFF in absolute value.  Use LongToIntoid to properly handle
  616. *       larger longs.
  617. *
  618. *   INPUTS
  619. *       ANumber - some signed or unsigned char, int or long.
  620. *
  621. *   RESULT
  622. *       MyIntoid - the Intoid equivalent, as a small integer form Intoid.
  623. *           Never returns NULL since it doesn't do memory allocation.
  624. *
  625. *   NOTES
  626. *       Only works for integers with absolute value of 0x3FFFFFFF or less.
  627. *       Defined in <libraries/Intoids.h>.
  628. *
  629. *   SEE ALSO
  630. *       LongToIntoid().
  631. *
  632. *****************************************************************************
  633. * looks like: define SmallIntToIntoid(x) ((Intoid) ((((long) (x)) << 1) | 1))
  634. */
  635.  
  636.  
  637.  
  638. /******************************************************************************
  639.  * Returns TRUE if the Intoid is a small integer, not a pointer.
  640.  * Small integers have the low bit set and the value in the rest of the bits.
  641.  */
  642.  
  643. #define IntoidIsSmallInt(x) (((IntoidAsLong) x) & 1)
  644.  
  645.  
  646.  
  647. /******************************************************************************
  648.  * Returns TRUE if the Intoid is a pointer to an IntRep.
  649.  * The intoid is a pointer if it is a multiple of 4 (assume memory allocation
  650.  * is aligned on 4 or more byte boundaries (Amiga's AllocMem is 8)).
  651.  * Watch out for double evaluation side effects with this one!
  652.  */
  653.  
  654. #define IntoidIsIntRep(x) (((x) != NULL) && ((((IntoidAsLong) (x)) & 3) == 0))
  655.  
  656.  
  657.  
  658. /******************************************************************************
  659.  * Returns TRUE if the Intoid contains a special code value.  Things like
  660.  * infinity are special codes.  Not-a-number is a special kind of special code,
  661.  * represented by a zero Intoid.
  662.  */
  663.  
  664. #define IntoidIsSpecialCode(x) (((x) == NULL) || \
  665. ((((IntoidAsLong) (x)) & 3) == 2))
  666.  
  667.  
  668.  
  669. /******************************************************************************
  670.  * Returns an Intoid for the special code.  Note that this doesn't work
  671.  * correctly for ISC_NOT_A_NUMBER (just use NULL instead).  Precomputed
  672.  * for INTOID_POSITIVE_INFINITY and INTOID_NEGATIVE_INFINITY.
  673.  */
  674.  
  675. #define SpecialCodeToIntoid(x) ((Intoid) (((long) (x)) * 4 + 2))
  676.  
  677.  
  678.  
  679. /******************************************************************************
  680.  * Returns the special code represented by the intoid.  Also happens to
  681.  * work for not-a-number (NULL) Intoids.
  682.  */
  683.  
  684. #define IntoidToSpecialCode(x) \
  685. ((IntoidSpecialCodes) (((IntoidAsLong) (x)) >> 2))
  686.  
  687.  
  688.  
  689. /******************************************************************************
  690.  * Returns the small integer an Intoid with the small integer coding
  691.  * represents.  You should check with IntoidIsSmallInt before using this
  692.  * function.
  693.  */
  694.  
  695. #define IntoidToSmallInt(x) (((IntoidAsLong) x) >> 1)
  696.  
  697.  
  698.  
  699. /******************************************************************************
  700.  * Get low order short's bits from a long.  Originally this was an inline
  701.  * function that and'ed the value with I_MAXNUM, but that generated
  702.  * inefficient code with SAS/C (mostly due to casting back and forth).
  703.  */
  704.  
  705. #define extract(x) ((unsigned short) (x))
  706.  
  707.  
  708.  
  709. /******************************************************************************
  710.  * Transfer high bits to low.  Again, this used to be an inline function
  711.  * that did (x >> I_SHIFT) & I_MAXNUM.
  712.  */
  713.  
  714. #define down(x) (x >> I_SHIFT)
  715.  
  716.  
  717.  
  718. /******************************************************************************
  719.  * Transfer low bits to high.  Another previously inline function.
  720.  */
  721.  
  722. #define up(x) (((unsigned long) (x)) << I_SHIFT)
  723.  
  724.  
  725.  
  726. /******************************************************************************
  727.  * Figure out max length of result of +, -, etc.  Returns the larger length
  728.  * plus the pad value.  Watch out, evaluates arguments twice.
  729.  */
  730.  
  731. #define  PadLargestLength(len1,len2,pad) \
  732. ((unsigned long) (((len1) >= (len2)) ? \
  733.   ((unsigned long) (len1) + (unsigned long) (pad)) : \
  734.   ((unsigned long) (len2) + (unsigned long) (pad))))
  735.  
  736.  
  737.  
  738. /******************************************************************************
  739.  * Compare two equal-length number arrays.  Returns x - y, only sign is
  740.  * meaningful (<0 for x<y, ==0 for x==y, >0 for x>y).
  741.  */
  742.  
  743. long LOCALFUNC __inline CompareNumberArrays (const unsigned short* x,
  744. const unsigned short* y, unsigned short l)
  745. {
  746.   long diff = 0;
  747.   const unsigned short* xs = &(x[l]);
  748.   const unsigned short* ys = &(y[l]);
  749.   while (l-- > 0 && (diff = (long) (*--xs) - (long) (*--ys)) == 0)
  750.     ;
  751.   return diff;
  752. }
  753.  
  754.  
  755.  
  756. /******************************************************************************
  757.  * Ensure array length & sign are correct (removes leading zeroes from number).
  758.  */
  759.  
  760. void LOCALFUNC __inline Icheck (IntRepPointer rep)
  761. {
  762.   unsigned short l = rep->currentLength;
  763.   const unsigned short* p = &(rep->numberArray[l]);
  764.  
  765.   while (l != 0 && *--p == 0)
  766.     --l;
  767.  
  768.   if ((rep->currentLength = (unsigned short) l) == 0)
  769.     rep->positiveSign = I_POSITIVE;
  770. }
  771.  
  772.  
  773.  
  774. /******************************************************************************
  775.  * Zero out the end of a rep, including allocated but unused space.
  776.  */
  777.  
  778. void LOCALFUNC __inline Iclear_from (IntRepPointer rep, unsigned short p)
  779. {
  780.   unsigned short* cp = &(rep->numberArray[p]);
  781.   const unsigned short* cf = &(rep->numberArray[rep->allocatedLength]);
  782.  
  783.   while(cp < cf)
  784.     *cp++ = 0;
  785. }
  786.  
  787.  
  788.  
  789. /******************************************************************************
  790.  * Zero out the part of a rep, from the given spot up to but not including
  791.  * the other spot's index.
  792.  */
  793.  
  794. void LOCALFUNC __inline Iclear_from_to (IntRepPointer rep,
  795. unsigned short From, unsigned short To)
  796. {
  797.   unsigned short* cp = &(rep->numberArray[From]);
  798.   const unsigned short* cf = &(rep->numberArray[To]);
  799.  
  800.   while(cp < cf)
  801.     *cp++ = 0;
  802. }
  803.  
  804.  
  805.  
  806.  
  807. /******************************************************************************
  808.  * Copy some of the number part of a rep to another.  Like memcpy but copies
  809.  * shorts rather than bytes and the arguments are reversed.
  810.  */
  811.  
  812. void LOCALFUNC __inline scpy (const unsigned short* src,
  813. unsigned short* dest, unsigned short nb)
  814. {
  815.   while (nb-- > 0)
  816.     *dest++ = *src++;
  817. }
  818.  
  819.  
  820.  
  821. /******************************************************************************
  822.  * Allocate a new Irep with the given number of shorts available for storage.
  823.  * Returns NULL if it fails.  Contents will be initialised to value for zero.
  824.  */
  825.  
  826. IntRepPointer LOCALFUNC Inew (unsigned long newlen)
  827. {
  828.   IntRepPointer rep;
  829.   unsigned long siz;
  830.  
  831.   if (newlen > MAXIntRep_SIZE)
  832.   {
  833.     DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_NEW_TOO_BIG));
  834.     return NULL;
  835.   }
  836.  
  837.   if (newlen < MINIntRep_SIZE)
  838.     newlen = MINIntRep_SIZE;
  839.   siz = sizeof(IntRep) +
  840.   ((unsigned long) newlen - 1 /* IntRep includes one short */) * sizeof(short);
  841.  
  842.   rep = AllocMem (siz,
  843.   MEMF_PUBLIC | MEMF_CLEAR /* Initialise new memory to zero */);
  844.  
  845.   if (rep == NULL)
  846.   {
  847.     DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_INTREP_OUT_OF_MEMORY));
  848.     return NULL;
  849.   }
  850.  
  851.   rep->allocatedLength = newlen;
  852.   rep->positiveSign = I_POSITIVE;
  853.   return rep;
  854. }
  855.  
  856.  
  857.  
  858. /******************************************************************************
  859.  * Deallocate an Irep.
  860.  */
  861.  
  862. void LOCALFUNC Idelete (IntRepPointer DeleteMe)
  863. {
  864.   unsigned long OldLength;
  865.  
  866.   if (DeleteMe != NULL && DeleteMe->allocatedLength != 0)
  867.   {
  868.     OldLength = DeleteMe->allocatedLength;
  869.     DeleteMe->allocatedLength = 0;  /* Just for debugging and safety. */
  870.     FreeMem (DeleteMe, sizeof (IntRep) +
  871.     (OldLength - 1 /* IntRep struct includes one short */) * sizeof (short));
  872.   }
  873. }
  874.  
  875.  
  876.  
  877. /******************************************************************************
  878.  * Internal function for resizing an IntRep, allocating space if it can't
  879.  * reuse the existing space.  Returns NULL if it fails.  CurrentLength is set
  880.  * to the new length and any extra words in the number are assumed to be zero
  881.  * (new leading digits are zero).  Also zeroes the whole number if requested.
  882.  */
  883.  
  884. IntRepPointer LOCALFUNC Iresize (IntRepPointer RecycleMe,
  885. unsigned long NewLength, BOOL ZeroNewValue)
  886. {
  887.   IntRepPointer   NewRep;
  888.   unsigned short  OldLength;
  889.  
  890.   if (RecycleMe == NULL)
  891.     NewRep = Inew (NewLength); /* Automatically zero value if successful. */
  892.   else
  893.   {
  894.     OldLength = RecycleMe->currentLength;
  895.     if (NewLength > RecycleMe->allocatedLength)
  896.     {
  897.       NewRep = Inew (NewLength);
  898.       if (NewRep != NULL && !ZeroNewValue)
  899.       {
  900.         scpy (RecycleMe->numberArray, NewRep->numberArray, OldLength);
  901.         NewRep->positiveSign = RecycleMe->positiveSign;
  902.       }
  903.       Idelete (RecycleMe);
  904.     }
  905.     else /* Reusing the IntRep.  Adjust it to the new size. */
  906.     {
  907.       NewRep = RecycleMe;
  908.       if (ZeroNewValue)
  909.       {
  910.         /* Just clear the non-zero part of the old one. */
  911.         Iclear_from_to (NewRep, 0, OldLength);
  912.         NewRep->positiveSign = I_POSITIVE;
  913.       }
  914.       else /* Just clear parts that shrink in size. */
  915.         Iclear_from_to (NewRep, (unsigned short) NewLength, OldLength);
  916.     }
  917.   }
  918.  
  919.   if (NewRep != NULL)
  920.     NewRep->currentLength = NewLength;
  921.  
  922.   return NewRep;
  923. }
  924.  
  925.  
  926.  
  927. /******************************************************************************
  928.  * Internal function for copying an IntRep to another one, allocating space
  929.  * if it can't overwrite the old one.  Handles NULL pointers and duplicate
  930.  * pointers.  Returns NULL if it fails.  Consider the old one deallocated
  931.  * after this function.
  932.  */
  933.  
  934. IntRepPointer LOCALFUNC Icopy (IntRepPointer old, const IntRepPointer src)
  935. {
  936.   unsigned short NewLength;
  937.   IntRepPointer  rep;
  938.  
  939.   if (old == src && old != NULL)
  940.     return old;
  941.  
  942.   if (src == NULL) /* Source doesn't exist. */
  943.   {
  944.     if (old == NULL)
  945.       return Inew (0 /* Minimum size will be used, new's value is zero */);
  946.  
  947.     Iclear_from_to (old, 0, old->currentLength);
  948.     old->currentLength = 0;
  949.     old->positiveSign = I_POSITIVE;
  950.     return old;
  951.   }
  952.  
  953.   /* Source exists.  Copy it. */
  954.  
  955.   NewLength = src->currentLength;
  956.  
  957.   if (old == NULL || NewLength > old->allocatedLength)
  958.   {
  959.     if (old != NULL) Idelete (old);
  960.     rep = Inew ((unsigned long) NewLength);
  961.     if (rep == NULL) return NULL;
  962.   }
  963.   else /* Can reuse the old one. */
  964.   {
  965.     /* Zero out unused things if old shrinks to new. */
  966.     Iclear_from_to (old, NewLength, old->currentLength);
  967.     rep = old;
  968.   }
  969.   rep->currentLength = NewLength;
  970.   rep->positiveSign = src->positiveSign;
  971.   scpy (src->numberArray, rep->numberArray, NewLength);
  972.  
  973.   return rep;
  974. }
  975.  
  976.  
  977.  
  978. /****** intoids.library/FreeIntoid ******************************************
  979. *
  980. *   NAME
  981. *       FreeIntoid -- Deallocates an Intoid.
  982. *
  983. *   SYNOPSIS
  984. *       FreeIntoid( RecycleMe )
  985. *                   A0
  986. *
  987. *       void FreeIntoid( Intoid );
  988. *
  989. *   FUNCTION
  990. *       Deallocates memory used by the given Intoid.  OK to pass in NULL.
  991. *       Like regular pointers, you shouldn't use the value in RecycleMe any
  992. *       more after calling this function.
  993. *
  994. *   INPUTS
  995. *       RecycleMe - a previously allocated Intoid or NULL.
  996. *
  997. *****************************************************************************
  998. */
  999.  
  1000. VOID LIBFUNC FreeIntoid (REGA0 Intoid RecycleMe)
  1001. {
  1002.   if (IntoidIsIntRep (RecycleMe))
  1003.   {
  1004.     Idelete ((IntoidAsPointer) RecycleMe);
  1005.   }
  1006. }
  1007.  
  1008.  
  1009.  
  1010. /******************************************************************************
  1011.  * Returns an Intoid set up as a pointer to an IntRep which contains at least
  1012.  * NewLength shorts in it's numberArray and currentLength set to NewLength.
  1013.  * If possible, the memory from RecycleMe is reused.  The new Intoid is set to
  1014.  * positive zero if requested, otherwise the value is copied from RecycleMe.
  1015.  * Returns NULL if it fails (RecycleMe is still deallocated in that case).
  1016.  */
  1017.  
  1018. Intoid LOCALFUNC ResizeIntoid (Intoid RecycleMe, unsigned long NewLength,
  1019. BOOL ZeroNewValue)
  1020. {
  1021.   IntRepPointer NewIntoid;
  1022.  
  1023.   NewIntoid = Iresize (IntoidIsIntRep (RecycleMe) ?
  1024.   (IntoidAsPointer) RecycleMe : NULL, NewLength, ZeroNewValue);
  1025.  
  1026.   return NewIntoid;
  1027. }
  1028.  
  1029.  
  1030.  
  1031. /******************************************************************************
  1032.  * Internal function for adding a Long to an IntRep based Intoid.  If NegateB
  1033.  * is TRUE then the negative of IntegerB will be added.  Handles the case
  1034.  * where RecycleMe is the same as IntegerB, avoiding extra allocations.
  1035.  * Doesn't normalize the result, so the result is always an IntRep or NULL.
  1036.  */
  1037.  
  1038. Intoid LOCALFUNC AddLongAndIntRep (long IntegerA, Intoid IntegerB,
  1039. BOOL NegateB, Intoid RecycleMe)
  1040. {
  1041.   long            ComparisonResult;
  1042.   unsigned short *DataResult;
  1043.   unsigned short *Data1Source;
  1044.   unsigned short *Data1SourceEnd;
  1045.   unsigned short *Data2Source;
  1046.   unsigned short *Data2SourceEnd;
  1047.   unsigned short  LengthA;
  1048.   unsigned short  LengthB;
  1049.   IntRepPointer   RepB;
  1050.   IntRepPointer   RepR;
  1051.   Intoid          Result;
  1052.   BOOL            SameBR;
  1053.   BOOL            SignA;
  1054.   BOOL            SignB;
  1055.   unsigned short  TempNumberArray [SHORT_PER_LONG];
  1056.   unsigned long   ULongA;
  1057.   unsigned long   ULongSum;
  1058.  
  1059.   if (!IntoidIsIntRep (IntegerB))
  1060.   {
  1061.     DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_BAD_INPUT_PARMS));
  1062.     FreeIntoid (RecycleMe);
  1063.     return NULL;  /* NULL input or wrong kind of intoid. */
  1064.   }
  1065.  
  1066.   RepB = (IntoidAsPointer) IntegerB;
  1067.   LengthB = RepB->currentLength;
  1068.   SignB = (NegateB && LengthB != 0) ? !RepB->positiveSign : RepB->positiveSign;
  1069.   SameBR = (IntegerB == RecycleMe);
  1070.  
  1071.   SignA = (IntegerA >= 0);
  1072.   ULongA = SignA ? IntegerA : -IntegerA;
  1073.  
  1074.   if (SignA == SignB) /* Just add the two unsigned values. */
  1075.   {
  1076.     Result = ResizeIntoid (RecycleMe,
  1077.     PadLargestLength (LengthB, SHORT_PER_LONG,
  1078.     1 /* Plus one extra short for overflows */),
  1079.     !SameBR /* Zero result if not same as IntegerB, else keep old value */);
  1080.  
  1081.     if (Result == NULL) return NULL; /* Out of memory. */
  1082.  
  1083.     RepR = (IntoidAsPointer) Result;
  1084.     RepR->positiveSign = SignB;
  1085.     DataResult = RepR->numberArray;
  1086.     Data1Source = SameBR ? DataResult : RepB->numberArray;
  1087.     Data1SourceEnd = Data1Source + LengthB;
  1088.     ULongSum = 0;
  1089.  
  1090.     while (Data1Source < Data1SourceEnd && ULongA != 0)
  1091.     {
  1092.       ULongSum += (unsigned long) (*Data1Source++) + extract (ULongA);
  1093.       ULongA = down (ULongA);
  1094.       *DataResult++ = extract (ULongSum);
  1095.       ULongSum = down (ULongSum);
  1096.     }
  1097.  
  1098.     while (ULongA != 0) /* Data source has run out first. */
  1099.     {
  1100.       ULongSum += extract (ULongA);
  1101.       ULongA = down (ULongA);
  1102.       *DataResult++ = extract (ULongSum);
  1103.       ULongSum = down (ULongSum);
  1104.     }
  1105.  
  1106.     while (ULongSum != 0 && Data1Source < Data1SourceEnd)
  1107.     {
  1108.       ULongSum += (unsigned long) (*Data1Source++);
  1109.       *DataResult++ = extract (ULongSum);
  1110.       ULongSum = down (ULongSum);
  1111.     }
  1112.  
  1113.     if (ULongSum != 0)
  1114.       *DataResult = extract (ULongSum); /* Overflowed after adding numbers. */
  1115.     else if (DataResult != Data1Source)  /* Copy rest of number if needed. */
  1116.       while (Data1Source < Data1SourceEnd)
  1117.         *DataResult++ = *Data1Source++;
  1118.   }
  1119.   else /* Doing a subtraction. */
  1120.   {
  1121.     /* Put the long value into an array of shorts format. */
  1122.  
  1123.     LengthA = 0;
  1124.     while (ULongA != 0)
  1125.     {
  1126.       TempNumberArray[LengthA++] = extract (ULongA);
  1127.       ULongA = down (ULongA);
  1128.     }
  1129.  
  1130.     /* See which one is bigger, IntegerA or IntegerB. */
  1131.  
  1132.     ComparisonResult = (long) LengthB - (long) LengthA;
  1133.     if (ComparisonResult == 0) /* Same length, compare values. */
  1134.       ComparisonResult = CompareNumberArrays (RepB->numberArray,
  1135.       TempNumberArray, LengthA);
  1136.  
  1137.     if (ComparisonResult == 0) /* Result should be zero. */
  1138.     {
  1139.       Result = ResizeIntoid (RecycleMe, 0, TRUE /* zero it */);
  1140.       if (Result == NULL) return NULL; /* Out of memory. */
  1141.       RepR = (IntoidAsPointer) Result;
  1142.     }
  1143.     else /* Do the math. */
  1144.     {
  1145.       Result = ResizeIntoid (RecycleMe,
  1146.       PadLargestLength (LengthB, SHORT_PER_LONG,
  1147.       0 /* no chance of overflow so no pad */),
  1148.       !SameBR /* Zero result if not same as IntegerB, else keep old value */);
  1149.       if (Result == NULL) return NULL; /* Out of memory. */
  1150.  
  1151.       RepR = (IntoidAsPointer) Result;
  1152.       DataResult = RepR->numberArray;
  1153.  
  1154.       if (ComparisonResult > 0) /* IntegerB > IntegerA */
  1155.       {
  1156.         Data1Source = SameBR ? DataResult : RepB->numberArray;
  1157.         Data1SourceEnd = Data1Source + LengthB;
  1158.         Data2Source = TempNumberArray;
  1159.         Data2SourceEnd = Data2Source + LengthA;
  1160.         RepR->positiveSign = SignB;
  1161.       }
  1162.       else /* IntegerB < IntegerA */
  1163.       {
  1164.         Data1Source = TempNumberArray;
  1165.         Data1SourceEnd = Data1Source + LengthA;
  1166.         Data2Source = SameBR ? DataResult : RepB->numberArray;
  1167.         Data2SourceEnd = Data2Source + LengthB;
  1168.         RepR->positiveSign = SignA;
  1169.       }
  1170.  
  1171.       /* Calculate  (1 << Largest Length) + Data1Source - Data2Source.
  1172.          The (1 << Largest Length) is too big to fit in the result,
  1173.          so it seems to be zero as far as the result is concerned.
  1174.          It's a way of doing the borrows without using negative numbers. */
  1175.  
  1176.       ULongSum = 1;
  1177.       while (Data2Source < Data2SourceEnd)
  1178.       {
  1179.         ULongSum += (unsigned long) (*Data1Source++) + I_MAXNUM -
  1180.         (unsigned long) (*Data2Source++);
  1181.         *DataResult++ = extract (ULongSum);
  1182.         ULongSum = down (ULongSum);
  1183.       }
  1184.  
  1185.       /* Finish off the Data1Source, which is known bigger than Data2Source. */
  1186.  
  1187.       while (ULongSum == 0 && Data1Source < Data1SourceEnd)
  1188.       {
  1189.         ULongSum = (unsigned long) (*Data1Source++) + I_MAXNUM;
  1190.         *DataResult++ = extract (ULongSum);
  1191.         ULongSum = down (ULongSum);
  1192.       }
  1193.  
  1194.       if (DataResult != Data1Source)  /* Copy rest of number if needed. */
  1195.         while (Data1Source < Data1SourceEnd)
  1196.           *DataResult++ = *Data1Source++;
  1197.     }
  1198.   }
  1199.   Icheck (RepR);
  1200.   return Result;
  1201. }
  1202.  
  1203.  
  1204.  
  1205. /******************************************************************************
  1206.  * Internal function for adding two IntRep based Intoids.  If NegateX is TRUE
  1207.  * then the negative of the appropriate IntegerX will be added. Handles the
  1208.  * case where RecycleMe is the same as IntegerX, avoiding extra allocations.
  1209.  * Doesn't normalize the result, so the result is always an IntRep or NULL.
  1210.  */
  1211.  
  1212. Intoid LOCALFUNC AddIntRepAndIntRep (Intoid IntegerA, BOOL NegateA,
  1213. Intoid IntegerB, BOOL NegateB, Intoid RecycleMe)
  1214. {
  1215.   long            ComparisonResult;
  1216.   unsigned short *DataResult;
  1217.   unsigned short *Data1Source;
  1218.   unsigned short *Data1SourceEnd;
  1219.   unsigned short *Data2Source;
  1220.   unsigned short *Data2SourceEnd;
  1221.   unsigned short  LengthA;
  1222.   unsigned short  LengthB;
  1223.   IntRepPointer   RepA;
  1224.   IntRepPointer   RepB;
  1225.   IntRepPointer   RepR;
  1226.   Intoid          Result;
  1227.   BOOL            SameAR;
  1228.   BOOL            SameBR;
  1229.   BOOL            SignA;
  1230.   BOOL            SignB;
  1231.   unsigned long   ULongSum;
  1232.  
  1233.   if (!IntoidIsIntRep (IntegerA) || !IntoidIsIntRep (IntegerB))
  1234.   {
  1235.     DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_BAD_INPUT_PARMS));
  1236.     FreeIntoid (RecycleMe);
  1237.     return NULL;  /* NULL input or wrong kind of intoid. */
  1238.   }
  1239.  
  1240.   RepA = (IntoidAsPointer) IntegerA;
  1241.   RepB = (IntoidAsPointer) IntegerB;
  1242.  
  1243.   LengthA = RepA->currentLength;
  1244.   LengthB = RepB->currentLength;
  1245.  
  1246.   SignA = (NegateA && LengthA != 0) ? !RepA->positiveSign : RepA->positiveSign;
  1247.   SignB = (NegateB && LengthB != 0) ? !RepB->positiveSign : RepB->positiveSign;
  1248.  
  1249.   SameAR = (IntegerA == RecycleMe);
  1250.   SameBR = (IntegerB == RecycleMe);
  1251.  
  1252.   if (SignA == SignB)
  1253.   {
  1254.     Result = ResizeIntoid (RecycleMe,
  1255.     PadLargestLength (LengthA, LengthB,
  1256.     1 /* Plus one extra short for overflows */),
  1257.     !(SameAR || SameBR) /* Zero result if result is not an input */);
  1258.  
  1259.     if (Result == NULL) return NULL; /* Out of memory. */
  1260.     RepR = (IntoidAsPointer) Result;
  1261.     RepR->positiveSign = SignA;
  1262.     DataResult = RepR->numberArray;
  1263.  
  1264.     /* Associate the longer number with Data1Source. */
  1265.  
  1266.     if (LengthA >= LengthB)
  1267.     {
  1268.       Data1Source = SameAR ? RepR->numberArray : RepA->numberArray;
  1269.       Data1SourceEnd = Data1Source + LengthA;
  1270.       Data2Source = SameBR ? RepR->numberArray : RepB->numberArray;
  1271.       Data2SourceEnd = Data2Source + LengthB;
  1272.     }
  1273.     else /* IntegerB is longer, it is used as Data1Source. */
  1274.     {
  1275.       Data1Source = SameBR ? RepR->numberArray : RepB->numberArray;
  1276.       Data1SourceEnd = Data1Source + LengthB;
  1277.       Data2Source = SameAR ? RepR->numberArray : RepA->numberArray;
  1278.       Data2SourceEnd = Data2Source + LengthA;
  1279.     }
  1280.     ULongSum = 0;
  1281.     while (Data2Source < Data2SourceEnd)
  1282.     {
  1283.       ULongSum += (unsigned long) (*Data1Source++) +
  1284.       (unsigned long) (*Data2Source++);
  1285.       *DataResult++ = extract (ULongSum);
  1286.       ULongSum = down (ULongSum);
  1287.     }
  1288.     while (ULongSum != 0 && Data1Source < Data1SourceEnd)
  1289.     {
  1290.       ULongSum += (unsigned long) (*Data1Source++);
  1291.       *DataResult++ = extract (ULongSum);
  1292.       ULongSum = down (ULongSum);
  1293.     }
  1294.     if (ULongSum != 0) /* Overflowed into last short. */
  1295.       *DataResult = extract (ULongSum);
  1296.     else /* Copy unchanging high part to result if needed. */
  1297.       if (DataResult != Data1Source)
  1298.         while (Data1Source < Data1SourceEnd)
  1299.           *DataResult++ = *Data1Source++;
  1300.   }
  1301.   else /* Different signs, do a subtraction. */
  1302.   {
  1303.     /* See which one is bigger, IntegerA or IntegerB. */
  1304.  
  1305.     ComparisonResult = (long) LengthA - (long) LengthB;
  1306.     if (ComparisonResult == 0) /* Same length, compare values. */
  1307.       ComparisonResult = CompareNumberArrays (RepA->numberArray,
  1308.       RepB->numberArray, LengthA);
  1309.  
  1310.     if (ComparisonResult == 0) /* Result should be zero. */
  1311.     {
  1312.       Result = ResizeIntoid (RecycleMe, 0, TRUE /* zero it */);
  1313.       if (Result == NULL) return NULL; /* Out of memory. */
  1314.       RepR = (IntoidAsPointer) Result;
  1315.     }
  1316.     else /* Do the math. */
  1317.     {
  1318.       Result = ResizeIntoid (RecycleMe,
  1319.       PadLargestLength (LengthA, LengthB,
  1320.       0 /* no need for overflow padding */),
  1321.       !(SameAR || SameBR) /* Zero result if result is not an input */);
  1322.  
  1323.       if (Result == NULL) return NULL; /* Out of memory. */
  1324.       RepR = (IntoidAsPointer) Result;
  1325.       DataResult = RepR->numberArray;
  1326.  
  1327.       /* Put the larger in magnitude integer in Data1Source. */
  1328.  
  1329.       if (ComparisonResult > 0) /* If IntegerA > IntegerB */
  1330.       {
  1331.         Data1Source = SameAR ? DataResult : RepA->numberArray;
  1332.         Data1SourceEnd = Data1Source + LengthA;
  1333.         Data2Source = SameBR ? DataResult : RepB->numberArray;
  1334.         Data2SourceEnd = Data2Source + LengthB;
  1335.         RepR->positiveSign = SignA;
  1336.       }
  1337.       else /* IntegerA < IntegerB */
  1338.       {
  1339.         Data1Source = SameBR ? DataResult : RepB->numberArray;
  1340.         Data1SourceEnd = Data1Source + LengthB;
  1341.         Data2Source = SameAR ? DataResult : RepA->numberArray;
  1342.         Data2SourceEnd = Data2Source + LengthA;
  1343.         RepR->positiveSign = SignB;
  1344.       }
  1345.  
  1346.       /* Calculate  (1 << Largest Length) + DataSource - Data2Source.
  1347.          The (1 << Largest Length) is too big to fit in the result,
  1348.          so it seems to be zero as far as the result is concerned.
  1349.          It's a way of doing the borrows without using negative numbers. */
  1350.  
  1351.       ULongSum = 1;
  1352.       while (Data2Source < Data2SourceEnd)
  1353.       {
  1354.         ULongSum += (unsigned long) (*Data1Source++) + I_MAXNUM -
  1355.         (unsigned long) (*Data2Source++);
  1356.         *DataResult++ = extract (ULongSum);
  1357.         ULongSum = down (ULongSum);
  1358.       }
  1359.  
  1360.       /* Finish off the Data1Source, which is known bigger than Data2Source. */
  1361.  
  1362.       while (ULongSum == 0 && Data1Source < Data1SourceEnd)
  1363.       {
  1364.         ULongSum = (unsigned long) (*Data1Source++) + I_MAXNUM;
  1365.         *DataResult++ = extract (ULongSum);
  1366.         ULongSum = down (ULongSum);
  1367.       }
  1368.  
  1369.       if (DataResult != Data1Source)  /* Copy rest of number if needed. */
  1370.         while (Data1Source < Data1SourceEnd)
  1371.           *DataResult++ = *Data1Source++;
  1372.     }
  1373.   }
  1374.   Icheck (RepR);
  1375.   return Result;
  1376. }
  1377.  
  1378.  
  1379.  
  1380. /******************************************************************************
  1381.  * Multiply a long and an IntRep based Intoid.
  1382.  * Returns an IntRep type Intoid or NULL.
  1383.  */
  1384.  
  1385. Intoid LOCALFUNC MultiplyLongAndIntRep (long IntegerA, const Intoid IntegerB,
  1386. Intoid RecycleMe)
  1387. {
  1388.   unsigned short *Data1Source;
  1389.   unsigned short *Data1SourceStart;
  1390.   unsigned short *Data2Source;
  1391.   unsigned short *Data2SourceEnd;
  1392.   unsigned short *Data2SourceStart;
  1393.   unsigned short *DataResult;
  1394.   unsigned short *DataResultCurrent;
  1395.   unsigned short *DataResultEnd;
  1396.   unsigned short  LengthA;
  1397.   unsigned short  LengthB;
  1398.   unsigned long   LengthR;
  1399.   unsigned long   Multiplier;
  1400.   IntRepPointer   RepB;
  1401.   IntRepPointer   RepR;
  1402.   Intoid          Result;
  1403.   BOOL            SameBR;
  1404.   BOOL            SignA;
  1405.   BOOL            SignB;
  1406.   BOOL            SignR;
  1407.   unsigned long   Sum;
  1408.   unsigned short  TempNumberArray [SHORT_PER_LONG];
  1409.   unsigned long   ULongA;
  1410.  
  1411.   /* Get ahold of the IntRep for IntegerB. */
  1412.  
  1413.   if (!IntoidIsIntRep (IntegerB))
  1414.   {
  1415.     DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_BAD_INPUT_PARMS));
  1416.     FreeIntoid (RecycleMe);
  1417.     return NULL;  /* NULL input or wrong kind of intoid. */
  1418.   }
  1419.   RepB = (IntoidAsPointer) IntegerB;
  1420.   LengthB = RepB->currentLength;
  1421.   SameBR = (IntegerB == RecycleMe);
  1422.  
  1423.   /* Check for the simple case of multiplying by zero. */
  1424.  
  1425.   if (LengthB == 0 || IntegerA == 0)
  1426.   {
  1427.     /* Multiplying by zero gives zero. */
  1428.  
  1429.     return ResizeIntoid (RecycleMe, 0, TRUE /* zero it */);
  1430.   }
  1431.  
  1432.   /* Check for the simple case of multiplying by one. */
  1433.  
  1434.   if (IntegerA == 1)
  1435.   {
  1436.     /* Multiplying by one gives the same number.   Use ResizeIntoid
  1437.        so that RecycleMe is guaranteed to be an IntRep.  Should
  1438.        also work if RecycleMe == IntegerB. */
  1439.  
  1440.     RecycleMe = ResizeIntoid (RecycleMe, (unsigned long) LengthB, FALSE);
  1441.     return Icopy (RecycleMe, IntegerB);
  1442.   }
  1443.  
  1444.   /* Figure out the sign of the result, before we start mangling it. */
  1445.  
  1446.   SignA = (IntegerA >= 0);
  1447.   SignB = RepB->positiveSign;
  1448.   SignR = (SignA == SignB);
  1449.  
  1450.   /* Copy our long number into a temporary array of shorts, and
  1451.      find out how long it is. */
  1452.  
  1453.   ULongA = SignA ? IntegerA : -IntegerA;
  1454.   LengthA = 0;
  1455.   while (ULongA != 0)
  1456.   {
  1457.     TempNumberArray[LengthA++] = extract (ULongA);
  1458.     ULongA = down (ULongA);
  1459.   }
  1460.  
  1461.   /* Allocate space for the result. */
  1462.  
  1463.   LengthR = (unsigned long) LengthA + (unsigned long) LengthB;
  1464.   Result = ResizeIntoid (RecycleMe, LengthR,
  1465.   !SameBR /* Zero result if not same as IntegerB, else keep old value */);
  1466.  
  1467.   if (Result == NULL) return NULL; /* Out of memory. */
  1468.   RepR = (IntoidAsPointer) Result;
  1469.   RepR->positiveSign = SignR;
  1470.  
  1471.   /* Set up pointers to sources and destinations. */
  1472.  
  1473.   DataResult = RepR->numberArray;
  1474.   DataResultEnd = DataResult + LengthR;
  1475.  
  1476.   if (SameBR)
  1477.   {
  1478.     DataResultCurrent = DataResult + (LengthB - 1);
  1479.     Data1SourceStart = DataResult;
  1480.     Data1Source = DataResultCurrent;
  1481.     Data2SourceStart = TempNumberArray;
  1482.     Data2SourceEnd = Data2SourceStart + LengthA;
  1483.   }
  1484.   else if (LengthB <= LengthA)
  1485.   {
  1486.     DataResultCurrent = DataResult + (LengthB - 1);
  1487.     Data1SourceStart = RepB->numberArray;
  1488.     Data1Source = Data1SourceStart + (LengthB - 1);
  1489.     Data2SourceStart = TempNumberArray;
  1490.     Data2SourceEnd = Data2SourceStart + LengthA;
  1491.   }
  1492.   else
  1493.   {
  1494.     DataResultCurrent = DataResult + (LengthA - 1);
  1495.     Data1SourceStart = TempNumberArray;
  1496.     Data1Source = Data1SourceStart + (LengthA - 1);
  1497.     Data2SourceStart = RepB->numberArray;
  1498.     Data2SourceEnd = Data2SourceStart + LengthB;
  1499.   }
  1500.  
  1501.   /* And now the big multiplication.  Much like you do in school grade 2. */
  1502.  
  1503.   while (Data1Source >= Data1SourceStart)
  1504.   {
  1505.     Multiplier = (unsigned long) (*Data1Source--);
  1506.     DataResult = DataResultCurrent--;
  1507.     *DataResult = 0;
  1508.     if (Multiplier != 0)
  1509.     {
  1510.       Sum = 0;
  1511.       Data2Source = Data2SourceStart;
  1512.       while (Data2Source < Data2SourceEnd)
  1513.       {
  1514.         Sum += Multiplier * (unsigned long) (*Data2Source++) +
  1515.         (unsigned long) (*DataResult);
  1516.         *DataResult++ = extract (Sum);
  1517.         Sum = down (Sum);
  1518.       }
  1519.       while (Sum != 0 && DataResult < DataResultEnd)
  1520.       {
  1521.         Sum += (unsigned long) (*DataResult);
  1522.         *DataResult++ = extract (Sum);
  1523.         Sum = down (Sum);
  1524.       }
  1525.     }
  1526.   }
  1527.  
  1528.   Icheck (RepR);
  1529.   return Result;
  1530. }
  1531.  
  1532.  
  1533.  
  1534. /******************************************************************************
  1535.  * Multiply two IntReps, returns an IntRep or NULL.
  1536.  * Assumes trivial cases done before this (arguments aren't 0 or +-1).
  1537.  * Recycles RecycleMe if it isn't NULL, can be the same as either argument or
  1538.  * both (special case code for squaring).
  1539.  */
  1540.  
  1541. IntRepPointer LOCALFUNC MultiplyIntRepAndIntRep (const IntRepPointer x,
  1542. const IntRepPointer y, Intoid RecycleMe)
  1543. {
  1544.   IntRepPointer   r;
  1545.   unsigned short  rl;  /* Result length. */
  1546.   unsigned long   rll; /* Long version of length to catch overflows. */
  1547.   unsigned short  xl;
  1548.   unsigned short  yl;
  1549.   int             rsgn;
  1550.   int             xrsame;
  1551.   int             yrsame;
  1552.   int             xysame;
  1553.  
  1554.   if (!IntoidIsIntRep (x) || !IntoidIsIntRep (y))
  1555.   {
  1556.     DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_BAD_INPUT_PARMS));
  1557.     FreeIntoid (RecycleMe);
  1558.     return NULL;
  1559.   }
  1560.  
  1561.   r = IntoidIsIntRep (RecycleMe) ? RecycleMe : NULL;
  1562.   xl  = x->currentLength;
  1563.   yl  = y->currentLength;
  1564.   rll = (unsigned long) xl + (unsigned long) yl;
  1565.   rl  = rll;
  1566.   rsgn = x->positiveSign == y->positiveSign;
  1567.   xrsame = x == r;
  1568.   yrsame = y == r;
  1569.   xysame = x == y;
  1570.  
  1571.   if (!(xysame && xrsame))
  1572.   {
  1573.     unsigned short* rs;
  1574.     unsigned short* topr;
  1575.     unsigned short* currentr;
  1576.     const unsigned short* bota;
  1577.     const unsigned short* as;
  1578.     const unsigned short* botb;
  1579.     const unsigned short* topb;
  1580.  
  1581.     r = Iresize (r, rll, !(xrsame || yrsame) /* Zero if different vars */);
  1582.     if (r == NULL) return NULL;
  1583.     rs = r->numberArray;
  1584.     topr = &(rs[rl]);
  1585.  
  1586.     /* use best inner/outer loop params given constraints */
  1587.     if (xrsame)
  1588.     {
  1589.       currentr = &(rs[xl-1]);
  1590.       bota = rs;
  1591.       as = currentr;
  1592.       botb = y->numberArray;
  1593.       topb = &(botb[yl]);
  1594.     }
  1595.     else if (yrsame)
  1596.     {
  1597.       currentr = &(rs[yl-1]);
  1598.       bota = rs;
  1599.       as = currentr;
  1600.       botb = x->numberArray;
  1601.       topb = &(botb[xl]);
  1602.     }
  1603.     else if (xl <= yl)
  1604.     {
  1605.       currentr = &(rs[xl-1]);
  1606.       bota = x->numberArray;
  1607.       as = &(bota[xl-1]);
  1608.       botb = y->numberArray;
  1609.       topb = &(botb[yl]);
  1610.     }
  1611.     else
  1612.     {
  1613.       currentr = &(rs[yl-1]);
  1614.       bota = y->numberArray;
  1615.       as = &(bota[yl-1]);
  1616.       botb = x->numberArray;
  1617.       topb = &(botb[xl]);
  1618.     }
  1619.  
  1620.     while (as >= bota)
  1621.     {
  1622.       unsigned long ai = (unsigned long)(*as--);
  1623.       unsigned short* rs = currentr--;
  1624.       *rs = 0;
  1625.       if (ai != 0)
  1626.       {
  1627.         unsigned long sum = 0;
  1628.         const unsigned short* bs = botb;
  1629.         while (bs < topb)
  1630.         {
  1631.           sum += ai * (unsigned long)(*bs++) + (unsigned long)(*rs);
  1632.           *rs++ = extract(sum);
  1633.           sum = down(sum);
  1634.         }
  1635.         while (sum != 0 && rs < topr)
  1636.         {
  1637.           sum += (unsigned long)(*rs);
  1638.           *rs++ = extract(sum);
  1639.           sum = down(sum);
  1640.         }
  1641.       }
  1642.     }
  1643.   }
  1644.   else /* x, y, and r same; compute over diagonals (squaring a number) */
  1645.   {
  1646.     unsigned short* botr;
  1647.     unsigned short* topr;
  1648.     unsigned short* rs;
  1649.     const unsigned short* bota;
  1650.     const unsigned short* loa;
  1651.     const unsigned short* hia;
  1652.  
  1653.     r = Iresize(r, rll, FALSE);
  1654.     if (r == NULL) return NULL;
  1655.     botr = r->numberArray;
  1656.     topr = &(botr[rl]);
  1657.     rs =   &(botr[rl - 2]);
  1658.  
  1659.     bota = (xrsame)? botr : x->numberArray;
  1660.     loa =  &(bota[xl - 1]);
  1661.     hia =  loa;
  1662.  
  1663.     for (; rs >= botr; --rs)
  1664.     {
  1665.       const unsigned short* h = hia;
  1666.       const unsigned short* l = loa;
  1667.       unsigned long prod = (unsigned long)(*h) * (unsigned long)(*l);
  1668.       *rs = 0;
  1669.  
  1670.       for(;;)
  1671.       {
  1672.         unsigned short* rt = rs;
  1673.         unsigned long sum = prod + (unsigned long)(*rt);
  1674.         *rt++ = extract(sum);
  1675.         sum = down(sum);
  1676.         while (sum != 0 && rt < topr)
  1677.         {
  1678.           sum += (unsigned long)(*rt);
  1679.           *rt++ = extract(sum);
  1680.           sum = down(sum);
  1681.         }
  1682.         if (h > l)
  1683.         {
  1684.           rt = rs;
  1685.           sum = prod + (unsigned long)(*rt);
  1686.           *rt++ = extract(sum);
  1687.           sum = down(sum);
  1688.           while (sum != 0 && rt < topr)
  1689.           {
  1690.             sum += (unsigned long)(*rt);
  1691.             *rt++ = extract(sum);
  1692.             sum = down(sum);
  1693.           }
  1694.           if (--h >= ++l)
  1695.             prod = (unsigned long)(*h) * (unsigned long)(*l);
  1696.           else
  1697.             break;
  1698.         }
  1699.         else
  1700.           break;
  1701.       }
  1702.       if (loa > bota)
  1703.         --loa;
  1704.       else
  1705.         --hia;
  1706.     }
  1707.   }
  1708.  
  1709.   r->positiveSign = rsgn;
  1710.   Icheck(r);
  1711.   return r;
  1712. }
  1713.  
  1714.  
  1715.  
  1716. /******************************************************************************
  1717.  * Divide by single digit, return remainder.
  1718.  * If q != 0, then keep the result in q, else just compute remainder.
  1719.  */
  1720.  
  1721. unsigned short LOCALFUNC unscale (const unsigned short* x, unsigned short xl,
  1722. unsigned short y, unsigned short* q)
  1723. {
  1724.   if (xl == 0 || y == 1)
  1725.     return 0;
  1726.   else if (q != 0)
  1727.   {
  1728.     unsigned short* botq = q;
  1729.     unsigned short* qs = &(botq[xl - 1]);
  1730.     const unsigned short* xs = &(x[xl - 1]);
  1731.     unsigned long rem = 0;
  1732.     while (qs >= botq)
  1733.     {
  1734.       unsigned long u;
  1735.       rem = up(rem) | *xs--;
  1736. #if _AMIGA && __SASC /* Use the utility.library 32 bit math subroutines. */
  1737.       u = UDivMod32 (rem, (unsigned long) y);
  1738.       rem = getreg (REG_D1);
  1739. #else /* Use compiler's 32 bit math. */
  1740.       u = rem / y;
  1741.       rem -= u * y;
  1742. #endif
  1743.       *qs-- = extract(u);
  1744.     }
  1745.     return (unsigned short) extract(rem);
  1746.   }
  1747.   else /* Same loop, a bit faster if just need rem. */
  1748.   {
  1749.     const unsigned short* botx = x;
  1750.     const unsigned short* xs = &(botx[xl - 1]);
  1751.     unsigned long rem = 0;
  1752.     while (xs >= botx)
  1753.     {
  1754.       rem = up(rem) | *xs--;
  1755. #if _AMIGA && __SASC /* Use the utility.library 32 bit math subroutines. */
  1756.       UDivMod32 (rem, (unsigned long) y);
  1757.       rem = getreg (REG_D1);
  1758. #else /* Use compiler's 32 bit math. */
  1759.       rem -= (rem / y) * y;
  1760. #endif
  1761.     }
  1762.     return (unsigned short) extract(rem);
  1763.   }
  1764. }
  1765.  
  1766.  
  1767.  
  1768. /******************************************************************************
  1769.  * Core division routine.
  1770.  */
  1771.  
  1772. void LOCALFUNC do_divide (unsigned short* rs,
  1773. const unsigned short* ys, unsigned short yl,
  1774. unsigned short* qs, unsigned short ql)
  1775. {
  1776.   const unsigned short* topy = &(ys[yl]);
  1777.   unsigned short d1 = ys[yl - 1];
  1778.   unsigned short d2 = ys[yl - 2];
  1779.  
  1780.   int l = ql - 1;
  1781.   int i = l + yl;
  1782.  
  1783.   for (; l >= 0; --l, --i)
  1784.   {
  1785.     unsigned short qhat;       /* guess q */
  1786.     if (d1 == rs[i])
  1787.       qhat = I_MAXNUM;
  1788.     else
  1789.     {
  1790.       unsigned long lr = up((unsigned long)rs[i]) | rs[i-1];
  1791.       qhat = lr / d1;
  1792.     }
  1793.  
  1794.     for(;;)  /* adjust q, use CompareNumberArrays to avoid overflow problems */
  1795.     {
  1796.       unsigned short ts[3];
  1797.       unsigned long prod = (unsigned long)d2 * (unsigned long)qhat;
  1798.       ts[0] = extract(prod);
  1799.       prod = down(prod) + (unsigned long)d1 * (unsigned long)qhat;
  1800.       ts[1] = extract(prod);
  1801.       ts[2] = extract(down(prod));
  1802.       if (CompareNumberArrays(ts, &(rs[i-2]), 3) > 0)
  1803.         --qhat;
  1804.       else
  1805.         break;
  1806.     };
  1807.  
  1808.     /* multiply & subtract */
  1809.  
  1810.     {
  1811.       const unsigned short* yt = ys;
  1812.       unsigned short* rt = &(rs[l]);
  1813.       unsigned long prod = 0;
  1814.       unsigned long hi = 1;
  1815.       while (yt < topy)
  1816.       {
  1817.         prod = (unsigned long)qhat * (unsigned long)(*yt++) + down(prod);
  1818.         hi += (unsigned long)(*rt) + I_MAXNUM - (unsigned long)(extract(prod));
  1819.         *rt++ = extract(hi);
  1820.         hi = down(hi);
  1821.       }
  1822.       hi += (unsigned long)(*rt) + I_MAXNUM - (unsigned long)(down(prod));
  1823.       *rt = extract(hi);
  1824.       hi = down(hi);
  1825.  
  1826.       /* off-by-one, add back */
  1827.  
  1828.       if (hi == 0)
  1829.       {
  1830.         --qhat;
  1831.         yt = ys;
  1832.         rt = &(rs[l]);
  1833.         hi = 0;
  1834.         while (yt < topy)
  1835.         {
  1836.           hi = (unsigned long)(*rt) + (unsigned long)(*yt++) + down(hi);
  1837.           *rt++ = extract(hi);
  1838.         }
  1839.         *rt = 0;
  1840.       }
  1841.       if (qs != 0)
  1842.         qs[l] = qhat;
  1843.     }
  1844.   }
  1845. }
  1846.  
  1847.  
  1848.  
  1849. /******************************************************************************
  1850.  * Divides an IntRep by a long.  Returns an IntRep or NULL.  Assumes
  1851.  * y != 0, x > y in magnitude (trivial cases done already).
  1852.  */
  1853.  
  1854. IntRepPointer LOCALFUNC DivideIntRepByLong (const IntRepPointer x, long y,
  1855. Intoid RecycleMe)
  1856. {
  1857.   IntRepPointer   q;
  1858.   unsigned short  xl;
  1859.   unsigned short  ys[SHORT_PER_LONG];
  1860.   unsigned long   u;
  1861.   int             xsgn;
  1862.   int             ysgn;
  1863.   int             samesign;
  1864.   unsigned short  yl;
  1865.   long            ql;
  1866.  
  1867.   if (!IntoidIsIntRep (x))
  1868.   {
  1869.     DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_BAD_INPUT_PARMS));
  1870.     FreeIntoid (RecycleMe);
  1871.     return NULL;
  1872.   }
  1873.  
  1874.   q = IntoidIsIntRep (RecycleMe) ? (IntoidAsPointer) RecycleMe : NULL;
  1875.   xl = x->currentLength;
  1876.   xsgn = x->positiveSign;
  1877.   ysgn = y >= 0;
  1878.   samesign = xsgn == ysgn;
  1879.   yl = 0;
  1880.  
  1881.   if (ysgn)
  1882.     u = y;
  1883.   else
  1884.     u = -y;
  1885.   while (u != 0)
  1886.   {
  1887.     ys[yl++] = extract(u);
  1888.     u = down(u);
  1889.   }
  1890.  
  1891.   if (yl == 1) /* If divisor fits in a short. */
  1892.   {
  1893.     q = Icopy(q, x);
  1894.     if (q == NULL) return NULL;
  1895.     unscale(q->numberArray, q->currentLength, ys[0], q->numberArray);
  1896.   }
  1897.   else
  1898.   {
  1899.     IntRepPointer r = NULL;
  1900.     unsigned short prescale = (I_RADIX / (1 + ys[yl - 1]));
  1901.     if (prescale != 1)
  1902.     {
  1903.       unsigned long prod = (unsigned long)prescale * (unsigned long)ys[0];
  1904.       ys[0] = extract(prod);
  1905.       prod = down(prod) + (unsigned long)prescale * (unsigned long)ys[1];
  1906.       ys[1] = extract(prod);
  1907.       r = MultiplyLongAndIntRep (((long)prescale & I_MAXNUM), x, r);
  1908.       if (r == NULL)
  1909.       {
  1910.         Idelete (q);
  1911.         return NULL;
  1912.       }
  1913.     }
  1914.     else
  1915.     {
  1916.       r = Iresize (r, xl + 1L, TRUE /* zero it */);
  1917.       if (r == NULL)
  1918.       {
  1919.         Idelete (q);
  1920.         return NULL;
  1921.       }
  1922.       scpy(x->numberArray, r->numberArray, xl);
  1923.     }
  1924.  
  1925.     ql = xl - yl + 1L;
  1926.     q = Iresize (q, ql, TRUE /* zero it */);
  1927.     if (q == NULL)
  1928.     {
  1929.       Idelete (r);
  1930.       return NULL;
  1931.     }
  1932.  
  1933.     do_divide(r->numberArray, ys, yl, q->numberArray, (unsigned short) ql);
  1934.  
  1935.     Idelete (r);
  1936.   }
  1937.   q->positiveSign = samesign;
  1938.   Icheck(q);
  1939.   return q;
  1940. }
  1941.  
  1942.  
  1943.  
  1944. /******************************************************************************
  1945.  * Divides an IntRep by another IntRep, returns an IntRep or NULL.  Assumes
  1946.  * y != 0, x > y in magnitude (trivial cases done already).
  1947.  */
  1948.  
  1949. IntRepPointer LOCALFUNC DivideIntRepByIntRep (const IntRepPointer x,
  1950. const IntRepPointer y, Intoid RecycleMe)
  1951. {
  1952.   IntRepPointer   q;
  1953.   unsigned short  xl;
  1954.   unsigned short  yl;
  1955.   int             xsgn;
  1956.   int             ysgn;
  1957.   int             samesign;
  1958.   long            ql;
  1959.  
  1960.   if (!IntoidIsIntRep (x) || !IntoidIsIntRep (y))
  1961.   {
  1962.     DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_BAD_INPUT_PARMS));
  1963.     FreeIntoid (RecycleMe);
  1964.     return NULL;
  1965.   }
  1966.  
  1967.   q = IntoidIsIntRep (RecycleMe) ? (IntoidAsPointer) RecycleMe : NULL;
  1968.   xl = x->currentLength;
  1969.   yl = y->currentLength;
  1970.   xsgn = x->positiveSign;
  1971.   ysgn = y->positiveSign;
  1972.   samesign = xsgn == ysgn;
  1973.  
  1974.   if (yl == 1) /* Fits in a short. */
  1975.   {
  1976.     q = Icopy(q, x);
  1977.     if (q == NULL) return NULL;
  1978.     unscale(q->numberArray, q->currentLength,
  1979.     y->numberArray[0], q->numberArray);
  1980.   }
  1981.   else
  1982.   {
  1983.     IntRepPointer yy = NULL;
  1984.     IntRepPointer r  = NULL;
  1985.     unsigned short prescale = (I_RADIX / (1 + y->numberArray[yl - 1]));
  1986.     if (prescale != 1 || y == q)
  1987.     {
  1988.       yy = MultiplyLongAndIntRep (((long)prescale & I_MAXNUM), y, yy);
  1989.       r = MultiplyLongAndIntRep (((long)prescale & I_MAXNUM), x, r);
  1990.       if (yy == NULL || r == NULL)
  1991.       {
  1992.         Idelete (r);
  1993.         Idelete (yy);
  1994.         Idelete (q);
  1995.         return NULL;
  1996.       }
  1997.     }
  1998.     else
  1999.     {
  2000.       yy = (IntRepPointer) y;
  2001.       r = Iresize (r, xl + 1L, TRUE /* zero it */);
  2002.       if (r == NULL)
  2003.       {
  2004.         Idelete (q);
  2005.         return NULL;
  2006.       }
  2007.       scpy(x->numberArray, r->numberArray, xl);
  2008.     }
  2009.  
  2010.     ql = xl - yl + 1L;
  2011.     q = Iresize (q, ql, TRUE /* zero it */);
  2012.     if (q == NULL)
  2013.     {
  2014.       Idelete (r);
  2015.       if (yy != y) Idelete (yy);
  2016.       return NULL;
  2017.     }
  2018.  
  2019.     do_divide(r->numberArray, yy->numberArray, yl, q->numberArray,
  2020.     (unsigned short) ql);
  2021.  
  2022.     if (yy != y) Idelete (yy);
  2023.     Idelete (r);
  2024.   }
  2025.   q->positiveSign = samesign;
  2026.   Icheck(q);
  2027.   return q;
  2028. }
  2029.  
  2030.  
  2031.  
  2032. /****** intoids.library/GetLastIntoidErrorMessage ***************************
  2033. *
  2034. *   NAME
  2035. *       GetLastIntoidErrorMessage -- Returns the latest error message.
  2036. *
  2037. *   SYNOPSIS
  2038. *       MyString = GetLastIntoidErrorMessage( )
  2039. *       D0
  2040. *
  2041. *       STRPTR GetLastIntoidErrorMessage( VOID );
  2042. *
  2043. *   FUNCTION
  2044. *       Returns a pointer to the last error message.  Maybe be incorrect if
  2045. *       you are using multitasking to cause errors (you get the global latest
  2046. *       error, not your latest error).  Also resets the error message to be
  2047. *       the copyright and credits for this library (you get that message if
  2048. *       there hasn't been an error since the last call to this function).
  2049. *
  2050. *   RESULT
  2051. *       MyString - a pointer to a read only string in your favorite language.
  2052. *
  2053. *   NOTES
  2054. *       The same message was displayed to the user in a system requester,
  2055. *       or maybe not if that feature is turned off by the user.
  2056. *
  2057. *****************************************************************************
  2058. */
  2059.  
  2060. STRPTR LIBFUNC GetLastIntoidErrorMessage (VOID)
  2061. {
  2062.   STRPTR ReturnPointer;
  2063.  
  2064.   ReturnPointer = (STRPTR) ErrorMessagePntr;
  2065.   ErrorMessagePntr = GetIntoidsMessage (MSG_INTOIDS_CREDITS);
  2066.   return ReturnPointer;
  2067. }
  2068.  
  2069.  
  2070.  
  2071. /******************************************************************************
  2072.  * Returns TRUE if the character is white space.  Uses Locale language library
  2073.  * if available, otherwise just hack it (avoid ctype array).
  2074.  */
  2075.  
  2076. BOOL LOCALFUNC MyIsSpace (unsigned long character)
  2077. {
  2078.   if (CurrentLocale != NULL)
  2079.     return IsSpace (CurrentLocale, character);
  2080.  
  2081.   return (BOOL) (character == ' ' || character == 9 /* tab char */);
  2082. }
  2083.  
  2084.  
  2085.  
  2086. /****** intoids.library/SignOfIntoid ****************************************
  2087. *
  2088. *   NAME
  2089. *       SignOfIntoid -- Returns -1, 0 or +1 depending on Intoid's sign.
  2090. *
  2091. *   SYNOPSIS
  2092. *       MySign = SignOfIntoid( IntegerA )
  2093. *       D0                     D0
  2094. *
  2095. *       LONG SignOfIntoid( Intoid );
  2096. *
  2097. *   FUNCTION
  2098. *       Fast way of finding the sign of any Intoid.
  2099. *
  2100. *   INPUTS
  2101. *       IntegerA - any Intoid you want to find the sign of.
  2102. *
  2103. *   RESULT
  2104. *       MySign - reflects the sign of IntegerA in a LONG value.  Returns -1
  2105. *           for negative integers (includes negative infinity), 0 for zero
  2106. *           and non-numbers, 1 for positive integers (and +infinity).
  2107. *
  2108. *   SEE ALSO
  2109. *       CompareIntoids(), CompareIntoidMagnitudes().
  2110. *
  2111. *****************************************************************************
  2112. */
  2113.  
  2114. LONG LIBFUNC SignOfIntoid (REGD0 Intoid IntegerA)
  2115. {
  2116.   IntRepPointer RepA;
  2117.   long          Sign;
  2118.  
  2119.   if (IntoidIsSmallInt (IntegerA))
  2120.   {
  2121.     Sign = IntoidToSmallInt (IntegerA);
  2122.     if (Sign < 0)
  2123.       Sign = -1L;
  2124.     else if (Sign > 0)
  2125.       Sign = 1L;
  2126.   }
  2127.   else if (IntoidIsIntRep (IntegerA))
  2128.   {
  2129.     RepA = (IntoidAsPointer) IntegerA;
  2130.     if (RepA->currentLength == 0) /* Value is IntRep equivalent to zero. */
  2131.       Sign = 0;
  2132.     else
  2133.       Sign = RepA->positiveSign ? 1L : -1L;
  2134.   }
  2135.   else if (IntegerA == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
  2136.     Sign = 1L;
  2137.   else if (IntegerA == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
  2138.     Sign = -1L;
  2139.   else /* Some other special code. */
  2140.     Sign = 0;
  2141.  
  2142.   return Sign;
  2143. }
  2144.  
  2145.  
  2146.  
  2147. /****** intoids.library/IntoidFitsInLong ************************************
  2148. *
  2149. *   NAME
  2150. *       IntoidFitsInLong -- Tests if an Intoid fits in a long int.
  2151. *
  2152. *   SYNOPSIS
  2153. *       Boolean = IntoidFitsInLong( IntegerA )
  2154. *       D0                          D0
  2155. *
  2156. *       BOOL IntoidFitsInLong( Intoid );
  2157. *
  2158. *   FUNCTION
  2159. *       Tests if an Intoid can be represented by an ordinary 32 bit long int.
  2160. *
  2161. *   INPUTS
  2162. *       IntegerA - any Intoid.
  2163. *
  2164. *   RESULT
  2165. *       Boolean - TRUE if the Intoid can fit into a long integer.  Numbers
  2166. *           too big, infinities and not-a-number return FALSE.
  2167. *
  2168. *   SEE ALSO
  2169. *       IntoidToLong().
  2170. *
  2171. *****************************************************************************
  2172. */
  2173.  
  2174. BOOL LIBFUNC IntoidFitsInLong (REGD0 Intoid IntegerA)
  2175. {
  2176.   int             i;
  2177.   IntRepPointer   MyIntRep;
  2178.   BOOL            ReturnValue;
  2179.  
  2180.   if (IntoidIsSmallInt (IntegerA))
  2181.     ReturnValue = TRUE;
  2182.   else if (IntoidIsIntRep (IntegerA))
  2183.   {
  2184.     MyIntRep = (IntoidAsPointer) IntegerA;
  2185.     if (MyIntRep->currentLength > SHORT_PER_LONG) /* More than 32 bits. */
  2186.       ReturnValue = FALSE;
  2187.     else if (MyIntRep->currentLength < SHORT_PER_LONG) /* Number has 16 bits or less. */
  2188.       ReturnValue = TRUE;
  2189.     else /* Unsigned value is same size as a long, 32 bits. */
  2190.     {
  2191.       if (MyIntRep->positiveSign) /* Positive OK if 0 to 0x7FFFFFFF. */
  2192.       {
  2193.         if (MyIntRep->numberArray [SHORT_PER_LONG-1] <= 0x7FFFU)
  2194.           ReturnValue = TRUE;
  2195.         else
  2196.           ReturnValue = FALSE;
  2197.       }
  2198.       else /* Negative with 32 bit value.  OK if whole is <= 0x80000000 */
  2199.       {
  2200.         if (MyIntRep->numberArray [SHORT_PER_LONG-1] <= 0x7FFFU)
  2201.           ReturnValue = TRUE;
  2202.         else if (MyIntRep->numberArray [SHORT_PER_LONG-1] == 0x8000U)
  2203.         {
  2204.           /* Check for special case value of 0x80000000. */
  2205.  
  2206.           i = SHORT_PER_LONG - 2;
  2207.           ReturnValue = TRUE;
  2208.           while (i >= 0)
  2209.           {
  2210.             if (MyIntRep->numberArray [i] != 0)
  2211.             {
  2212.               ReturnValue = FALSE; /* Nope, value is too big to fit. */
  2213.               break;
  2214.             }
  2215.             --i;
  2216.           }
  2217.         }
  2218.         else /* Negative value starting with 0x8001 or larger.  Too big. */
  2219.           ReturnValue = FALSE;
  2220.       }
  2221.     }
  2222.   }
  2223.   else
  2224.     ReturnValue = FALSE;  /* A special code, can't be represented. */
  2225.  
  2226.   return ReturnValue;
  2227. }
  2228.  
  2229.  
  2230.  
  2231. /****** intoids.library/IntoidToLong ****************************************
  2232. *
  2233. *   NAME
  2234. *       IntoidToLong -- Converts an Intoid into a long integer.
  2235. *
  2236. *   SYNOPSIS
  2237. *       MyLong = IntoidToLong( IntegerA )
  2238. *       D0                     D0
  2239. *
  2240. *       LONG IntoidToLong( Intoid );
  2241. *
  2242. *   FUNCTION
  2243. *       Converts an Intoid into the closest long integer.
  2244. *
  2245. *   INPUTS
  2246. *       IntegerA - any Intoid.
  2247. *
  2248. *   RESULT
  2249. *       MyLong - an ordinary 32 bit long int equal to IntegerA in value, if
  2250. *           possible.  If IntegerA is too big or too small then you get the
  2251. *           largest (0x7FFFFFFF) or smallest (0x80000000) long possible.
  2252. *           Plus and minus infinity become largest and smallest longs
  2253. *           respectively.  Not-a-number becomes zero.
  2254. *
  2255. *   SEE ALSO
  2256. *       IntoidFitsInLong().
  2257. *
  2258. *****************************************************************************
  2259. */
  2260.  
  2261. LONG LIBFUNC IntoidToLong (REGD0 Intoid IntegerA)
  2262. {
  2263.   int           i;
  2264.   IntRepPointer MyIntRep;
  2265.   unsigned long NewLong;
  2266.   long          ReturnValue;
  2267.  
  2268.   if (IntoidIsSmallInt (IntegerA))
  2269.     ReturnValue = IntoidToSmallInt (IntegerA);
  2270.   else if (IntoidIsIntRep (IntegerA))
  2271.   {
  2272.     MyIntRep = (IntoidAsPointer) IntegerA;
  2273.  
  2274.     if (MyIntRep->currentLength > SHORT_PER_LONG) /* More than 32 bits. */
  2275.     {
  2276.       if (MyIntRep->positiveSign)
  2277.         ReturnValue = LONG_MAX;
  2278.       else
  2279.         ReturnValue = LONG_MIN;
  2280.     }
  2281.     else if (MyIntRep->currentLength == 0)
  2282.       ReturnValue = 0;
  2283.     else if (MyIntRep->currentLength <= SHORT_PER_LONG - 1)
  2284.     {
  2285.       if (SHORT_PER_LONG > 2)
  2286.       {
  2287.         NewLong = 0;
  2288.         for (i = MyIntRep->currentLength - 1; i >= 0; i--)
  2289.           NewLong = up (NewLong) | MyIntRep->numberArray[i];
  2290.       }
  2291.       else /* 32 bit longs, know there is just 1 short in the number. */
  2292.         NewLong = MyIntRep->numberArray[0];
  2293.  
  2294.       if (MyIntRep->positiveSign)
  2295.         ReturnValue = (long) NewLong;
  2296.       else
  2297.         ReturnValue = -(long) NewLong;
  2298.     }
  2299.     else /* Value is same length as a long, may or may not overflow. */
  2300.     {
  2301.       /* Length is 2 shorts, 32 bits, may overflow since we have an unsigned 32
  2302.          bit value stored in numberArray and we are converting to a signed
  2303.          value. */
  2304.  
  2305.       if (SHORT_PER_LONG > 2)
  2306.       {
  2307.         NewLong = 0;
  2308.         for (i = SHORT_PER_LONG - 1; i >= 0; i--)
  2309.           NewLong = up (NewLong) | MyIntRep->numberArray[i];
  2310.       }
  2311.       else /* 32 bit longs, know there are 2 shorts in the number. */
  2312.         NewLong = up (MyIntRep->numberArray [1]) | MyIntRep->numberArray [0];
  2313.  
  2314.       if (MyIntRep->positiveSign) /* Positive OK if 0 to 0x7FFFFFFF. */
  2315.       {
  2316.         ReturnValue = (long) NewLong;
  2317.         if (ReturnValue < 0)  /* Too big, so it became negative. */
  2318.           ReturnValue = LONG_MAX; /* Use largest positive long instead. */
  2319.       }
  2320.       else /* Negative OK if 0 to 0x80000000. */
  2321.       {
  2322.         ReturnValue = -(long) NewLong;
  2323.         if (ReturnValue >= 0) /* Overflowed, and became positive. */
  2324.           ReturnValue = LONG_MIN; /* Use smallest long integer instead. */
  2325.       }
  2326.     }
  2327.   }
  2328.   else /* Must be a special code. */
  2329.   {
  2330.     switch (IntoidToSpecialCode (IntegerA))
  2331.     {
  2332.       case ISC_POSITIVE_INFINITY:
  2333.         ReturnValue = LONG_MAX;
  2334.         break;
  2335.  
  2336.       case ISC_NEGATIVE_INFINITY:
  2337.         ReturnValue = LONG_MIN;
  2338.         break;
  2339.  
  2340.       default:
  2341.         ReturnValue = 0;
  2342.         break;
  2343.     }
  2344.   }
  2345.  
  2346.   return ReturnValue;
  2347. }
  2348.  
  2349.  
  2350.  
  2351. /******************************************************************************
  2352.  * Converts a long integer into an IntRep.
  2353.  */
  2354.  
  2355. IntRepPointer LOCALFUNC LongToIntRep (const long LongA, Intoid RecycleMe)
  2356. {
  2357.   int           i;
  2358.   IntRepPointer MyIntRep;
  2359.   Intoid        NewIntoid;
  2360.   unsigned long TempLong;
  2361.  
  2362.   /* Ok, have to allocate an IntRep type representation, with at least 32 bits
  2363.      (2 shorts) of storage.  ResizeIntoid sets it's length to 2 shorts and
  2364.      sets the rest of the contents to zero, except the first 2 shorts. */
  2365.  
  2366.   NewIntoid = ResizeIntoid (RecycleMe, SHORT_PER_LONG,
  2367.   FALSE /* Don't need to zero it */);
  2368.   if (NewIntoid == NULL) return NULL;
  2369.  
  2370.   MyIntRep = (IntoidAsPointer) NewIntoid;
  2371.  
  2372.   if (LongA < 0)
  2373.   {
  2374.     MyIntRep->positiveSign = I_NEGATIVE;
  2375.     TempLong = -LongA;  /* Should work for even 0x80000000. */
  2376.   }
  2377.   else /* A positive or zero number. */
  2378.   {
  2379.     MyIntRep->positiveSign = I_POSITIVE;
  2380.     TempLong = LongA;
  2381.   }
  2382.  
  2383.   if (SHORT_PER_LONG > 2)
  2384.   {
  2385.     for (i = 0; i < SHORT_PER_LONG; i++)
  2386.     {
  2387.       MyIntRep->numberArray[i] = extract (TempLong);
  2388.       TempLong = down (TempLong);
  2389.     }
  2390.   }
  2391.   else /* SHORT_PER_LONG == 2 */
  2392.   {
  2393.     MyIntRep->numberArray[0] = extract (TempLong);
  2394.     MyIntRep->numberArray[1] = extract (down (TempLong));
  2395.   }
  2396.   Icheck (MyIntRep);  /* Reduce currentLength to remove leading zeroes. */
  2397.  
  2398.   return NewIntoid;
  2399. }
  2400.  
  2401.  
  2402.  
  2403. /****** intoids.library/LongToIntoid ****************************************
  2404. *
  2405. *   NAME
  2406. *       LongToIntoid -- Converts a long int to an Intoid.
  2407. *
  2408. *   SYNOPSIS
  2409. *       NewIntoid = LongToIntoid( LongA, RecycleMe )
  2410. *       D0                        D0     A0
  2411. *
  2412. *       Intoid LongToIntoid( LONG, Intoid );
  2413. *
  2414. *   FUNCTION
  2415. *       Converts a 32 bit long int into an Intoid.
  2416. *
  2417. *   INPUTS
  2418. *       LongA - the integer you want to convert.
  2419. *       RecycleMe - an old Intoid you want to deallocate, or NULL.
  2420. *
  2421. *   RESULT
  2422. *       NewIntoid - a newly allocated Intoid with value equal to LongA.  NULL
  2423. *           if out of memory.
  2424. *
  2425. *   SEE ALSO
  2426. *       SmallIntToIntoid().
  2427. *
  2428. *****************************************************************************
  2429. */
  2430.  
  2431. Intoid LIBFUNC LongToIntoid (REGD0 LONG LongA, REGA0 Intoid RecycleMe)
  2432. {
  2433.   /* If it fits in 31 bits, we can fit it into an Intoid as a small integer. */
  2434.  
  2435.   if ((unsigned long) (LONG_MIN >> 1) <= (unsigned long) LongA ||
  2436.   (unsigned long) LongA <= (unsigned long) (LONG_MAX >> 1))
  2437.   {
  2438.     FreeIntoid (RecycleMe);
  2439.     return SmallIntToIntoid (LongA);
  2440.   }
  2441.  
  2442.   return LongToIntRep (LongA, RecycleMe);
  2443. }
  2444.  
  2445.  
  2446.  
  2447. /******************************************************************************
  2448.  * Reduces the Intoid to the smallest representation technique that can hold
  2449.  * the number.  Returns the new Intoid, which may be different (the old
  2450.  * one may be deleted so don't have any other references to it).
  2451.  */
  2452.  
  2453. Intoid LOCALFUNC NormalizeIntoid (Intoid IntegerA)
  2454. {
  2455.   IntRepPointer Rep;
  2456.  
  2457.   if (IntoidIsSpecialCode (IntegerA)) /* Includes NULL case. */
  2458.     return IntegerA;
  2459.  
  2460.   if (IntoidIsSmallInt (IntegerA))
  2461.     return IntegerA;
  2462.  
  2463.   /* Must be an IntRep.  See if it fits in a small integer. */
  2464.  
  2465.   Rep = (IntoidAsPointer) IntegerA;
  2466.  
  2467.   if (Rep->currentLength > SHORT_PER_LONG)
  2468.     return IntegerA;  /* Definitely far too big to fit in 31 bits. */
  2469.  
  2470.   /* If the number might fit in 31 bits, including sign.
  2471.      Definitely fits in 32 bits, so convert to long and back
  2472.      (this also frees the IntRep if it isn't needed). */
  2473.  
  2474.   if (Rep->currentLength < SHORT_PER_LONG ||
  2475.   Rep->numberArray[SHORT_PER_LONG - 1] <= 0x4000U)
  2476.     return LongToIntoid (IntoidToLong (IntegerA), IntegerA);
  2477.  
  2478.   return IntegerA;
  2479. }
  2480.  
  2481.  
  2482.  
  2483. /****** intoids.library/--FileFormat-- **************************************
  2484. *
  2485. *   NAME
  2486. *       AGMSPortableIntFormat -- Description of the Portable Integer Format.
  2487. *
  2488. *   FUNCTION
  2489. *       This binary number format has to handle all values that could
  2490. *       be represented by an Intoid and has to be efficient in storage
  2491. *       space (so that the AGMS virtual file system databases aren't
  2492. *       too large).  It also has to be machine independant.
  2493. *
  2494. *       To make things simpler for current computer architectures, it is
  2495. *       based on a variable quantity of 8 bit bytes (almost all computers can
  2496. *       pick out an 8 bit byte from their memory efficiently, few can handle
  2497. *       arbitrarily large bit aligned data nicely, particularly in the C
  2498. *       language).
  2499. *
  2500. *       The general format is: FirstByte, optional size extension bytes,
  2501. *       optional data bytes.
  2502. *
  2503. *       The size extension byte(s) are located just after FirstByte and just
  2504. *       before the actual data bytes.  If the first size extension byte is
  2505. *       255 (all 1 bits) then the size value is in two bytes after that
  2506. *       (least significant byte comes first), and if those are all 1 bits
  2507. *       then the size is in the following 4 bytes, and so on, doubling in
  2508. *       length if the previous size extension value is all 1 bits.  Don't
  2509. *       use an extension of zero, that can cause trouble with some code
  2510. *       (extensions of zero are used to signal errors in the Intoids code).
  2511. *
  2512. *       The number of optional data bytes is defined by the FirstByte and
  2513. *       the optional size extension bytes.  Large integers are stored as a
  2514. *       positive magnitude (the sign is encoded in FirstByte) in the data
  2515. *       bytes.  The least significant byte comes first, followed by
  2516. *       increasingly more significant bytes.  This was done because it is
  2517. *       easier to shrink or expand from the end of an array rather than the
  2518. *       start of an array when a number gets smaller or larger.
  2519. *
  2520. *       The first byte can either be a small integer value (so that things
  2521. *       like file name string lengths fit in a byte) or part of a larger
  2522. *       integer or a special code.  Some numbers can be represented in
  2523. *       several different ways, you should be able to read all varieties,
  2524. *       and preferably write the shortest one.  Here is the encoding for the
  2525. *       first byte:
  2526. *
  2527. *       $0 to $7F:
  2528. *         A small positive integer with value 0 to 127 directly
  2529. *         corresponding to treating FirstByte as an 8 bit 2's complement
  2530. *         integer.
  2531. *
  2532. *       $96 to $FF:
  2533. *         A small negative integer with value -106 to -1 directly
  2534. *         corresponding to treating FirstByte as an 8 bit 2's complement
  2535. *         integer.
  2536. *
  2537. *       $80 to $87
  2538. *         A positive number with 1 to 8 bytes of data following the FirstByte.
  2539. *         The number of data bytes is (unsigned byte) FirstByte - $7F.  No
  2540. *         size extension bytes.
  2541. *
  2542. *       $88 to $8F
  2543. *         A negative number with 1 to 8 bytes of data following the FirstByte.
  2544. *         The number of data bytes is (unsigned byte) FirstByte - $87.  No
  2545. *         size extension bytes.
  2546. *
  2547. *       $90
  2548. *         A positive integer.  Has a size extension and a data section.  The
  2549. *         size extension specifies the number of bytes in the data section.
  2550. *
  2551. *       $91
  2552. *         A negative integer.  Has a size extension and a data section.  The
  2553. *         size extension specifies the number of bytes in the data section.
  2554. *
  2555. *       $92
  2556. *         Signals that an extended special code follows, the size extension
  2557. *         bytes specify the special code.  There is no data section.  Note
  2558. *         that we want to avoid a size extension of zero (causes trouble),
  2559. *         so the special codes start at 1.
  2560. *
  2561. *       $93 to $95
  2562. *         A special code number.  The particular one is FirstByte - $92.
  2563. *         There is no data section or size extension.  The special codes are:
  2564. *           1:  Positive integer infinity.
  2565. *           2:  Negative integer infinity.
  2566. *           3:  Not a number.  The NULL pointer of numbers.  The quiet kind
  2567. *               of not-a-number (doesn't raise error conditions when used).
  2568. *           4:  Noisy variety of not-a-number.  Generates an error if used
  2569. *               in math?  Intoids don't support it.  Uses FirstByte $92
  2570. *               style encoding.
  2571. *           5+: Future use, uses FirstByte $92 style for encoding.
  2572. *
  2573. *
  2574. *   EXAMPLE
  2575. *       00
  2576. *         A positive integer with a value of zero.  No size extension or
  2577. *         data bytes.
  2578. *
  2579. *       F6
  2580. *         A negative integer with a value of -10.  No size extension or
  2581. *         data bytes.
  2582. *
  2583. *       80 C8
  2584. *         A positive integer with no size extension and 1 ($80 - $7F = 1)
  2585. *         data byte.  It has a value of +200.
  2586. *
  2587. *       8B 00 CA 9A 3B
  2588. *         A negative integer with no size extension and 4 ($8B - $87 = 4)
  2589. *         data bytes.  It has a value of -$3B9ACA00 = -1000000000.
  2590. *
  2591. *       90 12 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18
  2592. *         A positive integer with a size extension of $12 = 18, and 18 data
  2593. *         bytes.  It has a value of $181716151413121110090807060504030201.
  2594. *
  2595. *       90 FF 23 01 (FF repeated 291 times)
  2596. *         A positive integer with a size extension of $123 = 291 (note the
  2597. *         first size extension byte is $FF which means see the next two
  2598. *         bytes ($23 $01) for the size extension).  The data section has
  2599. *         291 bytes of $FF each.  This is an integer with a value of
  2600. *         2^2328 - 1.
  2601. *
  2602. *       93
  2603. *         Special code 1, meaning positive infinity.
  2604. *
  2605. *       94
  2606. *         Special code 2, meaning negative infinity.
  2607. *
  2608. *       95
  2609. *         This is special code 3, the code for a quiet not-a-number.
  2610. *
  2611. *       92 04
  2612. *         Special code number 4, error signalling variety of not-a-number.
  2613. *
  2614. *       92 FF 23 01
  2615. *         Special code number $123 = 291.  Currently not defined to mean
  2616. *         anything (future use).  No data section even though it has size
  2617. *         extension bytes.
  2618. *
  2619. *       91 FF FF FF 78 56 34 12 01 02 03 [and 305419893 more bytes here]
  2620. *         This is a negative integer with $12345678 = 305419896 bytes of
  2621. *         number in the data section.  Note the way the size extension grew
  2622. *         to hold the size of $12345678.  Most current computers would have
  2623. *         trouble loading this 300 megabyte number into memory, let alone
  2624. *         multiplying it with another one.
  2625. *
  2626. *****************************************************************************
  2627. */
  2628.  
  2629.  
  2630.  
  2631. /****** intoids.library/--UserCallBackStreamFunction-- **********************
  2632. *
  2633. *   NAME
  2634. *       AGMSPortableIntStreamCallBack -- User defined function for stream IO.
  2635. *
  2636. *   SYNOPSIS
  2637. *       LONG STACKCALL AGMSPortableIntStreamCallBack (
  2638. *         ULONG Operation, APTR Buffer, LONG Amount, APTR UserPntr );
  2639. *
  2640. *   FUNCTION
  2641. *       A user defined callback function that is used for reading and writing
  2642. *       AGMS Portable Integer numbers from or to a stream.
  2643. *
  2644. *   INPUTS
  2645. *       Operation - this argument specifies what your function should do:
  2646. *           0:  Read data.  Fill the buffer with Amount data bytes.  Your
  2647. *               function returns the amount read, which will be less than
  2648. *               the Amount requested if it fails (end of file etc).
  2649. *           1:  Seek.  Seek relative to the current stream postion by
  2650. *               Amount bytes.  Amount is negative for seeking backwards,
  2651. *               but PortableInt functions will never do that.  Returns
  2652. *               the position in the stream if known, or just zero when
  2653. *               it succeeds, returns -1 if it fails (seek past EOF or
  2654. *               before start of file, IO errors).  Return -2 if you don't
  2655. *               implement seek, and a bunch of reads will be used instead.
  2656. *           2:  Write data.  Write Amount bytes from the buffer to the
  2657. *               stream.  Returns the amount written, which  will be less
  2658. *               than the Amount requested if it fails (IO error etc).
  2659. *           N:  For other unsupported Operation values please return -2.
  2660. *       Buffer - points to a buffer where the read in data is saved or
  2661. *         the data to be written is obtained.
  2662. *       Amount - used to specify the number of bytes to
  2663. *         read, skip over, or write.
  2664. *       UserPntr - the same value as passed into the original
  2665. *         PortableInt function call.  Usually will be a file
  2666. *         handle or something similar.
  2667. *
  2668. *   RESULT
  2669. *       ActualAmount - the function returns the number of bytes actually
  2670. *           read or written, or the absolute file position after a seek.
  2671. *
  2672. *   NOTES
  2673. *       The callback function is called using the C language stack
  2674. *       based calling convention.  In SAS C this is specified with
  2675. *       the __stdargs keywords.
  2676. *
  2677. *   BUGS
  2678. *       Returned seek position value only good for files up to 2G.
  2679. *
  2680. *   SEE ALSO
  2681. *       PortIntCallBackOp enum in Intoids.h, STACKCALL macro in Intoids.h.
  2682. *
  2683. *****************************************************************************
  2684. */
  2685.  
  2686.  
  2687.  
  2688. /******************************************************************************
  2689.  * Read the multibyte extension number from the stream.  Returns 0 if
  2690.  * something goes wrong.  The extension is initially 1 byte long, if that is
  2691.  * all 1 bits (value 0xFF) then read the next two bytes.  If they are all
  2692.  * 1's then read the next 4 bytes, and so on, doubling the number of bytes
  2693.  * read.  Fails if the extension value is too big for a long integer.  Also
  2694.  * returns the number of bytes actually read, if ByteCountPntr isn't NULL.
  2695.  */
  2696.  
  2697. ULONG LOCALFUNC ReadExtensionValue (PortIntCallBackPntr CallBack,
  2698. APTR UserPntr, ULONG *ByteCountPntr)
  2699. {
  2700.   LONG  ActualIOResult;
  2701.   UBYTE ByteArray [CHAR_PER_LONG];
  2702.   ULONG ByteCount;
  2703.   ULONG ExtensionFullCode;
  2704.   ULONG ExtensionValue;
  2705.   int   i;
  2706.   LONG  ReadSize;
  2707.  
  2708.   ByteCount = 0;
  2709.   ReadSize = 1;
  2710.   ExtensionValue = ExtensionFullCode = 0;
  2711.  
  2712.   while (ExtensionValue == ExtensionFullCode)
  2713.   {
  2714.     if (ReadSize > CHAR_PER_LONG)
  2715.     {
  2716.       /* Extension is bigger than what fits in a long. */
  2717.  
  2718.       DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_BAD_FORMAT));
  2719.       ExtensionValue = 0; /* Signal an error. */
  2720.       break;
  2721.     }
  2722.  
  2723.     /* Read in the next extension value's bytes. */
  2724.  
  2725.     ActualIOResult = (* CallBack) (PICBOP_READ, ByteArray, ReadSize, UserPntr);
  2726.     ByteCount += ActualIOResult;
  2727.     if (ActualIOResult != ReadSize)
  2728.     {
  2729.       DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_READ_ERROR));
  2730.       ExtensionValue = 0; /* Signal an error. */
  2731.       break;
  2732.     }
  2733.  
  2734.     /* Convert from little endian to native format. */
  2735.  
  2736.     ExtensionValue = 0;
  2737.     for (i = ReadSize - 1; i >= 0 ; --i)
  2738.     {
  2739.       ExtensionValue <<= 8;
  2740.       ExtensionValue |= ByteArray[i];
  2741.     }
  2742.  
  2743.     /* Generate all 1 bits in ReadSize bytes for
  2744.        the current ExtensionFullCode. */
  2745.  
  2746.     ExtensionFullCode = (1UL << (8 * ReadSize)) - 1UL;
  2747.  
  2748.     /* Double the size for next read attempt. */
  2749.  
  2750.     ReadSize += ReadSize;
  2751.   }
  2752.  
  2753.   /* Return the results. */
  2754.  
  2755.   if (ByteCountPntr != NULL)
  2756.     *ByteCountPntr = ByteCount;
  2757.  
  2758.   return ExtensionValue;
  2759. }
  2760.  
  2761.  
  2762.  
  2763. /******************************************************************************
  2764.  * Read the header information from an AGMS Portable Integer.  Returns
  2765.  * optional number of bytes read, kind of number, auxiliary value (either
  2766.  * the small integer or special code or number of bytes in a large integer),
  2767.  * and a success flag (TRUE for success, FALSE for error).  Fails on IO
  2768.  * errors and size extension field being too big to fit in a long.
  2769.  */
  2770.  
  2771. typedef enum NumberTypeEnum
  2772. {
  2773.   PI_SPECIAL_CODE,
  2774.   PI_SMALL_INTEGER,
  2775.   PI_LARGE_POSITIVE_INTEGER,
  2776.   PI_LARGE_NEGATIVE_INTEGER,
  2777. } NumberType;
  2778.  
  2779. BOOL LOCALFUNC ReadPortableIntHeader (PortIntCallBackPntr CallBack,
  2780. APTR UserPntr, ULONG *ByteCountPntr, NumberType *NumberKindPntr,
  2781. ULONG *AuxiliaryDataPntr)
  2782. {
  2783.   LONG        ActualIOResult;
  2784.   ULONG       AuxiliaryData;
  2785.   ULONG       ByteCount;
  2786.   UBYTE       FirstByte;
  2787.   NumberType  NumberKind;
  2788.   BOOL        ReturnCode;
  2789.   UBYTE       UByteOnStack;
  2790.   ULONG       ULongOnStack;
  2791.  
  2792.   ReturnCode = FALSE;  /* Default failure. */
  2793.   ByteCount = AuxiliaryData = NumberKind = 0;
  2794.  
  2795.   if (CallBack == NULL)
  2796.   {
  2797.     DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_BAD_INPUT_PARMS));
  2798.     goto FunctionExit;
  2799.   }
  2800.  
  2801.   /* Get the FirstByte of the number. */
  2802.  
  2803.   ActualIOResult = (* CallBack) (PICBOP_READ, &UByteOnStack, 1, UserPntr);
  2804.   FirstByte = UByteOnStack;
  2805.   ByteCount += ActualIOResult;
  2806.   if (ActualIOResult != 1)
  2807.   {
  2808.     DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_READ_ERROR));
  2809.     goto FunctionExit;
  2810.   }
  2811.  
  2812.   /* Decode the NumberKind and read size extension if needed. */
  2813.  
  2814.   if (FirstByte <= 0x7FU) /* A positive small integer. */
  2815.   {
  2816.     NumberKind = PI_SMALL_INTEGER;
  2817.     AuxiliaryData = FirstByte;
  2818.   }
  2819.   else if (FirstByte >= 0x96U) /* A negative small integer. */
  2820.   {
  2821.     NumberKind = PI_SMALL_INTEGER;
  2822.     AuxiliaryData = (long) (signed char) FirstByte;  /* Sign extend it. */
  2823.   }
  2824.   else if (FirstByte <= 0x87U) /* A positive large integer, $80 to $87. */
  2825.   {
  2826.     NumberKind = PI_LARGE_POSITIVE_INTEGER;
  2827.     AuxiliaryData = FirstByte - 0x7FU;  /* Length in bytes. */
  2828.   }
  2829.   else if (FirstByte <= 0x8FU) /* A negative large integer, $88 to $8F. */
  2830.   {
  2831.     NumberKind = PI_LARGE_NEGATIVE_INTEGER;
  2832.     AuxiliaryData = FirstByte - 0x87U;  /* Length in bytes. */
  2833.   }
  2834.   else if (FirstByte == 0x90U) /* A positive large integer, variable size. */
  2835.   {
  2836.     NumberKind = PI_LARGE_POSITIVE_INTEGER;
  2837.     AuxiliaryData = ReadExtensionValue (CallBack, UserPntr, &ULongOnStack);
  2838.     ByteCount += ULongOnStack;
  2839.     if (AuxiliaryData == 0)
  2840.       goto FunctionExit; /* Error while reading size extension. */
  2841.   }
  2842.   else if (FirstByte == 0x91U) /* A negative large integer, variable size. */
  2843.   {
  2844.     NumberKind = PI_LARGE_NEGATIVE_INTEGER;
  2845.     AuxiliaryData = ReadExtensionValue (CallBack, UserPntr, &ULongOnStack);
  2846.     ByteCount += ULongOnStack;
  2847.     if (AuxiliaryData == 0)
  2848.       goto FunctionExit; /* Error while reading size extension. */
  2849.   }
  2850.   else if (FirstByte == 0x92U) /* A special code, size is code's value. */
  2851.   {
  2852.     NumberKind = PI_SPECIAL_CODE;
  2853.     AuxiliaryData = ReadExtensionValue (CallBack, UserPntr, &ULongOnStack);
  2854.     ByteCount += ULongOnStack;
  2855.     if (AuxiliaryData == 0)
  2856.       goto FunctionExit; /* Error while reading size extension. */
  2857.   }
  2858.   else /* $93 to $95, a special code. */
  2859.   {
  2860.     NumberKind = PI_SPECIAL_CODE;
  2861.     AuxiliaryData = FirstByte - 0x92U;
  2862.   }
  2863.  
  2864.   ReturnCode = TRUE;  /* Success at last. */
  2865.  
  2866. FunctionExit:
  2867.   /* Stuff the return values into their memory locations. */
  2868.  
  2869.   if (ByteCountPntr != NULL)
  2870.     *ByteCountPntr = ByteCount;
  2871.  
  2872.   *NumberKindPntr = NumberKind;
  2873.   *AuxiliaryDataPntr = AuxiliaryData;
  2874.  
  2875.   return ReturnCode;
  2876. }
  2877.  
  2878.  
  2879.  
  2880. /******************************************************************************
  2881.  * This callback function converts a buffer into a stream.  In other words, it
  2882.  * handles reading, writing and seeking.  The end of the buffer corresponds to
  2883.  * the end of the stream.  See PortIntCallBackPntr in Intoids.h for details.
  2884.  */
  2885.  
  2886. typedef struct BufferStreamStruct
  2887. {
  2888.   UBYTE *start;   /* Points to start of user's buffer. */
  2889.   UBYTE *end;     /* Points just past end of user's buffer. */
  2890.   UBYTE *current; /* Current position in user's buffer. */
  2891. } BufferStreamRecord, *BufferStreamPointer;
  2892.  
  2893.  
  2894. LONG STACKCALL BufferAsStreamCallBack (ULONG Operation, APTR Buffer,
  2895. LONG Amount, APTR UserPntr)
  2896. {
  2897.   LONG ActualAmount;
  2898.  
  2899.   BufferStreamPointer UsersBufferInfo;
  2900.  
  2901.   UsersBufferInfo = UserPntr;
  2902.  
  2903.   switch (Operation)
  2904.   {
  2905.     case PICBOP_READ:
  2906.       ActualAmount = UsersBufferInfo->end - UsersBufferInfo->current;
  2907.       if (ActualAmount > Amount)
  2908.         ActualAmount = Amount;
  2909.       if (ActualAmount > 0)
  2910.       {
  2911.         memcpy (Buffer, UsersBufferInfo->current, (size_t) ActualAmount);
  2912.         UsersBufferInfo->current += ActualAmount;
  2913.       }
  2914.       else /* Zero or negative amount to copy.  Do nothing. */
  2915.         ActualAmount = 0;
  2916.       return ActualAmount;
  2917.  
  2918.     case PICBOP_SEEK:
  2919.       if (Amount >= 0)
  2920.       {
  2921.         ActualAmount = UsersBufferInfo->end - UsersBufferInfo->current;
  2922.         if (ActualAmount >= Amount) /* Enough space to do the seek. */
  2923.         {
  2924.           UsersBufferInfo->current += Amount;
  2925.           return UsersBufferInfo->current - UsersBufferInfo->start;
  2926.         }
  2927.         return -1; /* Can't seek that far. */
  2928.       }
  2929.       /* Seeking backwards. */
  2930.       ActualAmount = UsersBufferInfo->start - UsersBufferInfo->current;
  2931.       if (ActualAmount <= Amount) /* Enough space to do the seek. */
  2932.       {
  2933.         UsersBufferInfo->current += Amount;
  2934.         return UsersBufferInfo->current - UsersBufferInfo->start;
  2935.       }
  2936.       return -1; /* Can't seek that far. */
  2937.  
  2938.     case PICBOP_WRITE:
  2939.       ActualAmount = UsersBufferInfo->end - UsersBufferInfo->current;
  2940.       if (ActualAmount > Amount)
  2941.         ActualAmount = Amount;
  2942.       if (ActualAmount > 0)
  2943.       {
  2944.         memcpy (UsersBufferInfo->current, Buffer, (size_t) ActualAmount);
  2945.         UsersBufferInfo->current += ActualAmount;
  2946.       }
  2947.       else /* Zero or negative amount to copy.  Do nothing. */
  2948.         ActualAmount = 0;
  2949.       return ActualAmount;
  2950.   }
  2951.  
  2952.   return -2; /* Unimplemented operation. */
  2953. }
  2954.  
  2955.  
  2956.  
  2957. /****** intoids.library/PortableIntLengthViaCallBack ************************
  2958. *
  2959. *   NAME
  2960. *       PortableIntLengthViaCallBack -- Gets byte size of portable integer.
  2961. *
  2962. *   SYNOPSIS
  2963. *       Length = PortableIntLengthViaCallBack( CallBack, UserPntr )
  2964. *       D0                                     D0        D1
  2965. *
  2966. *       ULONG PortableIntLengthViaCallBack( PortIntCallBackPntr, APTR );
  2967. *
  2968. *   FUNCTION
  2969. *       Finds the length in bytes of an AGMS Portable Integer and skips
  2970. *       over it.
  2971. *
  2972. *   INPUTS
  2973. *       CallBack - a user provided function that handles the input
  2974. *           stream, see the intoids.library/AGMSPortableIntStreamCallBack
  2975. *           entry in these autodocs for details.
  2976. *       UserPntr - Any pointer sized value you want.  This value will be
  2977. *           passed to your callback function.  Typically used for file
  2978. *           handles.
  2979. *
  2980. *   RESULT
  2981. *       Length - returns the length or zero if something went wrong (read
  2982. *           error or unsupported number kind or bad number format, in which
  2983. *           case an unknown number of bytes will have been read).  Length
  2984. *           includes the header size.
  2985. *
  2986. *   NOTES
  2987. *       As a side effect, it has read all the bytes in the number.  You can
  2988. *       use this function to skip over a number (it seeks past the number
  2989. *       contents for big numbers).
  2990. *
  2991. *   BUGS
  2992. *       Doesn't work for numbers that take more than 2 Gigabytes of storage
  2993. *       space (garbage results in that case, and unpredictable number of
  2994. *       bytes read in that case too - but then that would be a very big
  2995. *       number that nobody would ever use, well except when trying to foil
  2996. *       nanotechnology based decryption systems :-).
  2997. *
  2998. *   SEE ALSO
  2999. *       PortableIntLengthViaBuffer(), AGMSPortableIntStreamCallBack.
  3000. *
  3001. *****************************************************************************
  3002. */
  3003.  
  3004. ULONG LIBFUNC PortableIntLengthViaCallBack (
  3005.   REGD0 PortIntCallBackPntr CallBack,
  3006.   REGD1 APTR UserPntr)
  3007. {
  3008.   LONG  ActualIOResult;
  3009.   ULONG Amount;
  3010.   ULONG ByteCount;
  3011.   ULONG DataSize;
  3012.   ULONG NumberKind;
  3013.   char  TempBuffer [20];
  3014.  
  3015.   if (!ReadPortableIntHeader (CallBack, UserPntr,
  3016.   &ByteCount, &NumberKind, &DataSize))
  3017.     return 0;  /* Some sort of error. */
  3018.  
  3019.   /* Skip over the actual data bytes, if any. */
  3020.  
  3021.   if (NumberKind == PI_LARGE_POSITIVE_INTEGER ||
  3022.   NumberKind == PI_LARGE_NEGATIVE_INTEGER)
  3023.   {
  3024.     ActualIOResult = (* CallBack) (PICBOP_SEEK, NULL, DataSize, UserPntr);
  3025.     if (ActualIOResult == -1 /* Seek returns -1 for errors. */)
  3026.     {
  3027.       DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_SEEK_ERROR));
  3028.       return 0;
  3029.     }
  3030.     if (ActualIOResult == -2 /* Seek returns -2 for unimplemented. */)
  3031.     {
  3032.       /* Simulate a seek by doing a bunch of reads. */
  3033.  
  3034.       while (DataSize > 0)
  3035.       {
  3036.         if (DataSize > sizeof (TempBuffer))
  3037.           Amount = sizeof (TempBuffer);
  3038.         else
  3039.           Amount = DataSize;
  3040.  
  3041.         ActualIOResult = (* CallBack) (PICBOP_READ,
  3042.         TempBuffer, Amount, UserPntr);
  3043.         ByteCount += ActualIOResult;
  3044.         DataSize -= ActualIOResult;
  3045.  
  3046.         if (ActualIOResult != Amount)
  3047.         {
  3048.           DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_READ_ERROR));
  3049.           return 0;
  3050.         }
  3051.       }
  3052.     }
  3053.     else /* Successful seek. */
  3054.       ByteCount += DataSize;
  3055.   }
  3056.  
  3057.   return ByteCount;
  3058. }
  3059.  
  3060.  
  3061.  
  3062. /****** intoids.library/PortableIntLengthViaBuffer **************************
  3063. *
  3064. *   NAME
  3065. *       PortableIntLengthViaBuffer -- Gets byte size of portable integer.
  3066. *
  3067. *   SYNOPSIS
  3068. *       Length = PortableIntLengthViaBuffer( Buffer, BufferSize )
  3069. *       D0                                   A0      D1
  3070. *
  3071. *       ULONG PortableIntLengthViaBuffer( APTR, ULONG );
  3072. *
  3073. *   FUNCTION
  3074. *       Finds the length in bytes of an AGMS Portable Integer in a buffer.
  3075. *
  3076. *   INPUTS
  3077. *       Buffer - points to an area of memory containing the portable integer.
  3078. *       BufferSize - amount of data in the buffer.
  3079. *
  3080. *   RESULT
  3081. *       Length - returns the length or zero if something went wrong (hit end
  3082. *           of buffer before number completed, unsupported number kind or bad
  3083. *           number format).  Length includes the header size.
  3084. *
  3085. *   BUGS
  3086. *       Doesn't work for numbers that take more than 2 Gigabytes of storage
  3087. *       space (garbage results in that case - but then that would be a very
  3088. *       big number that nobody would ever use, well maybe we could return an
  3089. *       Intoid instead of a ULONG :-).
  3090. *
  3091. *   SEE ALSO
  3092. *       PortableIntLengthViaCallBack().
  3093. *
  3094. *****************************************************************************
  3095. */
  3096.  
  3097. ULONG LIBFUNC PortableIntLengthViaBuffer (
  3098.   REGA0 APTR Buffer,
  3099.   REGD1 ULONG BufferSize)
  3100. {
  3101.   BufferStreamRecord  BufferAsStream;
  3102.  
  3103.   BufferAsStream.current = BufferAsStream.start = Buffer;
  3104.   BufferAsStream.end = (UBYTE *) Buffer + BufferSize;
  3105.  
  3106.   return PortableIntLengthViaCallBack (BufferAsStreamCallBack,
  3107.   &BufferAsStream);
  3108. }
  3109.  
  3110.  
  3111.  
  3112. /****** intoids.library/PortableIntToIntoidViaCallBack **********************
  3113. *
  3114. *   NAME
  3115. *       PortableIntToIntoidViaCallBack -- Converts portable int to Intoid.
  3116. *
  3117. *   SYNOPSIS
  3118. *       NewIntoid = PortableIntToIntoidViaCallBack
  3119. *                   ( CallBack, UserPntr, AmountReadPntr, RecycleMe )
  3120. *       D0            A0        D0        A1              D1
  3121. *
  3122. *       Intoid PortableIntToIntoidViaCallBack
  3123. *              ( PortIntCallBackPntr, APTR, ULONG *, Intoid );
  3124. *
  3125. *   FUNCTION
  3126. *       Reads an arbitrarily long integer in AGMS Portable Integer format
  3127. *       from some input stream and returns the result as an Intoid.
  3128. *
  3129. *   INPUTS
  3130. *       CallBack - a user provided function that handles the input
  3131. *           stream, see the intoids.library/AGMSPortableIntStreamCallBack
  3132. *           entry in these autodocs for details.
  3133. *       UserPntr - Any pointer sized value you want.  This value will be
  3134. *           passed to your callback function.  Typically used for file
  3135. *           handles.
  3136. *       AmountReadPntr - points to a long variable where the number of bytes
  3137. *           read will be placed.  Set to NULL if you don't want to use this
  3138. *           feature.
  3139. *       RecycleMe - an old Intoid you want to deallocate, or NULL.
  3140. *
  3141. *   RESULT
  3142. *       NewIntoid - an Intoid equivalent to the number, or NULL if it fails,
  3143. *           also NULL if the number is not-a-number.
  3144. *       AmountReadPntr - pointed to variable is updated with the number of
  3145. *           bytes that were actually read.
  3146. *
  3147. *   NOTES
  3148. *       Advances the stream to just past the number, if it succeded.
  3149. *
  3150. *   BUGS
  3151. *       Doesn't work with numbers over 2G in storage space, but they won't fit
  3152. *       in an Intoid anyways (128K bytes max in an Intoid).
  3153. *
  3154. *   SEE ALSO
  3155. *       PortableIntToIntoidViaBuffer(), AGMSPortableIntStreamCallBack.
  3156. *
  3157. *****************************************************************************
  3158. */
  3159.  
  3160. Intoid LIBFUNC PortableIntToIntoidViaCallBack (
  3161.   REGA0 PortIntCallBackPntr CallBack,
  3162.   REGD0 APTR UserPntr,
  3163.   REGA1 ULONG *AmountReadPntr,
  3164.   REGD1 Intoid RecycleMe)
  3165. {
  3166.   ULONG           AuxiliaryData;
  3167.   LONG            ActualIOResult;
  3168.   ULONG           ByteCount;
  3169.   Intoid          NewIntoid;
  3170.   IntRepPointer   NewIntRep;
  3171.   NumberType      NumberKind;
  3172.   unsigned short *ShortPntr;
  3173.   ULONG           ShortSize;
  3174.   BOOL            Success;
  3175.   unsigned short  TempShort;
  3176.   ULONG           ULongOnStack;
  3177.  
  3178.   NewIntoid = NULL;  /* Default return value for error conditions. */
  3179.   ByteCount = 0;
  3180.  
  3181.   Success = ReadPortableIntHeader (CallBack, UserPntr, &ULongOnStack,
  3182.   &NumberKind, &AuxiliaryData);
  3183.   ByteCount += ULongOnStack;
  3184.   if (!Success)  /* Error while reading header? */
  3185.   {
  3186.     FreeIntoid (RecycleMe);
  3187.     goto FunctionExit;
  3188.   }
  3189.  
  3190.   switch (NumberKind)
  3191.   {
  3192.     case PI_SMALL_INTEGER:
  3193.       NewIntoid = SmallIntToIntoid (AuxiliaryData);
  3194.       break;
  3195.  
  3196.  
  3197.     case PI_LARGE_POSITIVE_INTEGER:
  3198.     case PI_LARGE_NEGATIVE_INTEGER:
  3199.  
  3200.       /* Allocate an Intoid large enough to hold the number. */
  3201.  
  3202.       ShortSize = (AuxiliaryData + sizeof (short) - 1) / sizeof (short);
  3203.       if (ShortSize <= 0) /* Some sort of bug. */
  3204.       {
  3205.         DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_BAD_FORMAT));
  3206.         FreeIntoid (RecycleMe);
  3207.         break;
  3208.       }
  3209.       NewIntoid = ResizeIntoid (RecycleMe, ShortSize,
  3210.       FALSE /* don't bother zeroing ShortSize part of it */);
  3211.       if (NewIntoid == NULL)
  3212.         break; /* Out of memory. */
  3213.       NewIntRep = (IntoidAsPointer) NewIntoid;
  3214.  
  3215.       /* Read in the number's magnitude bytes. */
  3216.  
  3217.       NewIntRep->numberArray[ShortSize-1] = 0; /* So high byte is zero. */
  3218.       ActualIOResult = (* CallBack) (PICBOP_READ, NewIntRep->numberArray,
  3219.       AuxiliaryData, UserPntr);
  3220.       ByteCount += ActualIOResult;
  3221.       if (ActualIOResult != AuxiliaryData)
  3222.       {
  3223.         DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_READ_ERROR));
  3224.         FreeIntoid (NewIntoid);
  3225.         NewIntoid = NULL;
  3226.         break;
  3227.       }
  3228.  
  3229.       /* Reverse the bytes in each short integer, if this computer
  3230.          uses most significant byte first order. */
  3231.  
  3232. #if _M68000 /* Motorola 68000 series CPUs uses MSB order. */
  3233.       ShortPntr = NewIntRep->numberArray + ShortSize;
  3234.       do
  3235.       {
  3236.         TempShort = *--ShortPntr;
  3237.         *ShortPntr = (TempShort << 8) | (TempShort >> 8);
  3238.       } while (ShortPntr != NewIntRep->numberArray);
  3239. #endif /* _M68000 */
  3240.  
  3241.       /* Normalise the result so it is a valid Intoid. */
  3242.  
  3243.       NewIntRep->positiveSign = (NumberKind == PI_LARGE_POSITIVE_INTEGER);
  3244.       Icheck (NewIntRep);
  3245.       NewIntoid = NormalizeIntoid (NewIntoid);
  3246.       break;
  3247.  
  3248.  
  3249.     case PI_SPECIAL_CODE:
  3250.       FreeIntoid (RecycleMe);
  3251.       if (AuxiliaryData == 1)
  3252.       {
  3253.         NewIntoid = INTOID_POSITIVE_INFINITY;
  3254.         break;
  3255.       }
  3256.       else if (AuxiliaryData == 2)
  3257.       {
  3258.         NewIntoid = INTOID_NEGATIVE_INFINITY;
  3259.         break;
  3260.       }
  3261.       else if (AuxiliaryData == 3 || AuxiliaryData == 4)
  3262.       {
  3263.         NewIntoid = NULL; /* Quiet and noisy not-a-number become NULL. */
  3264.         break;
  3265.       }
  3266.       /* Otherwise an unknown special code. */
  3267.       DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_BAD_FORMAT));
  3268.       break;
  3269.  
  3270.  
  3271.     default: /* Unknown kind. */
  3272.       FreeIntoid (RecycleMe);
  3273.       DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_BAD_FORMAT));
  3274.       break;
  3275.   }
  3276.  
  3277.   /* Set various return values and return. */
  3278.  
  3279. FunctionExit:
  3280.   if (AmountReadPntr != NULL)
  3281.     *AmountReadPntr = ByteCount;
  3282.  
  3283.   return NewIntoid;
  3284. }
  3285.  
  3286.  
  3287.  
  3288. /****** intoids.library/PortableIntToIntoidViaBuffer ************************
  3289. *
  3290. *   NAME
  3291. *       PortableIntToIntoidViaBuffer -- Converts portable int to Intoid.
  3292. *
  3293. *   SYNOPSIS
  3294. *       NewIntoid = PortableIntToIntoidViaBuffer
  3295. *                   ( Buffer, BufferSize, AmountReadPntr, RecycleMe )
  3296. *       D0            A0      D0          A1              D1
  3297. *
  3298. *       Intoid PortableIntToIntoidViaBuffer( APTR, ULONG, ULONG *, Intoid );
  3299. *
  3300. *   FUNCTION
  3301. *       Reads an arbitrarily long integer in AGMS Portable Integer format
  3302. *       from a buffer and returns the Intoid equivalent.
  3303. *
  3304. *   INPUTS
  3305. *       Buffer - points to an area of memory containing the portable integer.
  3306. *       BufferSize - amount of data in the buffer.  Has to be at least
  3307. *           enough for the entire portable integer, or you get NULL returned.
  3308. *       AmountReadPntr - points to a long variable where the number of bytes
  3309. *           read will be placed.  Set to NULL if you don't want to use this
  3310. *           feature.
  3311. *       RecycleMe - an old Intoid you want to deallocate, or NULL.
  3312. *
  3313. *   RESULT
  3314. *       NewIntoid - an Intoid equivalent to the number, or NULL if it fails,
  3315. *           also NULL if the number is not-a-number.
  3316. *       AmountReadPntr - pointed to variable is updated with the number of
  3317. *           bytes that were actually read, will be from zero to BufferSize.
  3318. *
  3319. *   BUGS
  3320. *       Doesn't work with numbers over 2G in storage space, but they won't fit
  3321. *       in an Intoid anyways (128K bytes max in an Intoid) or even in most
  3322. *       system's memory.
  3323. *
  3324. *   SEE ALSO
  3325. *       PortableIntToIntoidViaCallBack().
  3326. *
  3327. *****************************************************************************
  3328. */
  3329.  
  3330. Intoid LIBFUNC PortableIntToIntoidViaBuffer (
  3331.   REGA0 APTR Buffer,
  3332.   REGD0 ULONG BufferSize,
  3333.   REGA1 ULONG *AmountReadPntr,
  3334.   REGD1 Intoid RecycleMe)
  3335. {
  3336.   BufferStreamRecord  BufferAsStream;
  3337.  
  3338.   BufferAsStream.current = BufferAsStream.start = Buffer;
  3339.   BufferAsStream.end = (UBYTE *) Buffer + BufferSize;
  3340.  
  3341.   return PortableIntToIntoidViaCallBack (BufferAsStreamCallBack,
  3342.   &BufferAsStream, AmountReadPntr, RecycleMe);
  3343. }
  3344.  
  3345.  
  3346.  
  3347. /****** intoids.library/IntoidToPortableIntViaCallBack **********************
  3348. *
  3349. *   NAME
  3350. *       IntoidToPortableIntViaCallBack -- Converts Intoid to portable int.
  3351. *
  3352. *   SYNOPSIS
  3353. *       Success = IntoidToPortableIntViaCallBack
  3354. *                ( AnIntoid, BytesWrittenPntr, CallBack, UserPntr)
  3355. *       D0         D0        A0                D1        A1
  3356. *
  3357. *       BOOL IntoidToPortableIntViaCallBack
  3358. *            ( Intoid, ULONG *, PortIntCallBackPntr, APTR );
  3359. *
  3360. *   FUNCTION
  3361. *       Writes the AGMS Portable Integer binary format equivalent of the
  3362. *       Intoid to a stream using a callback function.  Also tests to see if
  3363. *       your compiler can handle 30 letter function names :-).
  3364. *
  3365. *   INPUTS
  3366. *       AnIntoid - the Intoid big integer to be converted.
  3367. *       BytesWrittenPntr - points to a ULONG that will be set to the number
  3368. *           of bytes written, specify NULL if you aren't using this feature.
  3369. *       CallBack - a user provided function that handles the input
  3370. *           stream, see the intoids.library/AGMSPortableIntStreamCallBack
  3371. *           entry in these autodocs for details.
  3372. *       UserPntr - Any pointer sized value you want.  This value will be
  3373. *           passed to your callback function.  Typically used for file
  3374. *           handles.
  3375. *
  3376. *   RESULT
  3377. *       Success - returns TRUE (1) if successful, FALSE (0) if it fails.
  3378. *       BytesWrittenPntr - the pointed to ULONG is set to the number of
  3379. *           bytes actually written.  If you have an IO error then this
  3380. *           will be less than the actual size (see PortableIntSizeOfIntoid())
  3381. *           for the number.
  3382. *
  3383. *   SEE ALSO
  3384. *       PortableIntSizeOfIntoid(), IntoidToPortableIntViaBuffer(),
  3385. *       AGMSPortableIntStreamCallBack.
  3386. *
  3387. *****************************************************************************
  3388. */
  3389.  
  3390. BOOL LIBFUNC IntoidToPortableIntViaCallBack (
  3391.   REGD0 Intoid AnIntoid,
  3392.   REGA0 ULONG *BytesWrittenPntr,
  3393.   REGD1 PortIntCallBackPntr CallBack,
  3394.   REGA1 APTR UserPntr)
  3395. {
  3396.   ULONG               AmountToWrite;
  3397.   ULONG               AmountWritten;
  3398.   IntRepPointer       AnIntRep;
  3399.   UBYTE               ByteArray[8];  /* Even size, FirstByte + size extension */
  3400.   ULONG               ByteCount;
  3401.   ULONG               BytesNeeded;
  3402.   unsigned short      CurrentShort;
  3403.   LONG                LongValue;
  3404.   unsigned short     *NextShortPntr;
  3405.   BOOL                Negative;
  3406.   BOOL                ReturnCode;
  3407.   IntoidSpecialCodes  SpecialCode;
  3408.   LONG                TempLong;
  3409.  
  3410.   ByteCount = 0;
  3411.   ReturnCode = FALSE;
  3412.  
  3413.   if (IntoidIsSmallInt (AnIntoid))
  3414.   {
  3415.     LongValue = IntoidToSmallInt (AnIntoid);
  3416.     if (-106 <= LongValue && LongValue <= 127)
  3417.     {
  3418.       /* This integer can be represented as a single byte. */
  3419.  
  3420.       ByteArray [0] = (UBYTE) LongValue;
  3421.       AmountToWrite = 1;
  3422.     }
  3423.     else /* Doesn't fit directly in a byte, need a variable length type. */
  3424.     {
  3425.       TempLong = (Negative = (LongValue < 0)) ? -LongValue : LongValue;
  3426.       BytesNeeded = 0;
  3427.       while (TempLong)
  3428.       {
  3429.         ByteArray [BytesNeeded + 1] = (UBYTE) TempLong;
  3430.         BytesNeeded++;
  3431.         TempLong >>= 8;
  3432.       }
  3433.       ByteArray [0] = (Negative ? 0x87 : 0x7F) + BytesNeeded;
  3434.       AmountToWrite = BytesNeeded + 1;
  3435.     }
  3436.  
  3437.     /* Write the encoded number in ByteArray. */
  3438.  
  3439.     AmountWritten = (* CallBack) (PICBOP_WRITE, ByteArray, AmountToWrite,
  3440.     UserPntr);
  3441.     ByteCount += AmountWritten;
  3442.     if (AmountWritten != AmountToWrite)
  3443.       DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_WRITE_ERROR));
  3444.     else /* Success */
  3445.       ReturnCode = TRUE;
  3446.   }
  3447.   else if (IntoidIsIntRep (AnIntoid))
  3448.   {
  3449.     AnIntRep = (IntoidAsPointer) AnIntoid;
  3450.  
  3451.     if (AnIntRep->currentLength <= 0) /* Shouldn't happen, but... */
  3452.     {
  3453.       ByteArray [0] = 0; /* Code for small integer zero. */
  3454.       AmountToWrite = 1; /* Size of header to write. */
  3455.       BytesNeeded = 0;  /* Number of body data bytes to write. */
  3456.     }
  3457.     else /* Have some data to write.  How much? */
  3458.     {
  3459.       BytesNeeded = AnIntRep->currentLength * 2;
  3460.       if (AnIntRep->numberArray [AnIntRep->currentLength - 1] < 256)
  3461.         --BytesNeeded;  /* High byte of high word is zero. */
  3462.  
  3463.       if (BytesNeeded <= 8) /* Fits in 1 to 8 bytes special code? */
  3464.       {
  3465.         ByteArray [0] = (AnIntRep->positiveSign ? 0x7F : 0x87) + BytesNeeded;
  3466.         AmountToWrite = 1;
  3467.       }
  3468.       else /* Have lots of bytes to write, need size extension. */
  3469.       {
  3470.         ByteArray [0] = (AnIntRep->positiveSign ? 0x90 : 0x91);
  3471.  
  3472.         if (BytesNeeded < 0xFF) /* Fits in a byte?  0xFF used for extension. */
  3473.         {
  3474.           ByteArray [1] = (UBYTE) BytesNeeded;
  3475.           AmountToWrite = 2;
  3476.         }
  3477.         else if (BytesNeeded < 0xFFFF)  /* Fits in 2 bytes? */
  3478.         {
  3479.           ByteArray [1] = 0xFF; /* Marks doubling of size extension. */
  3480.           ByteArray [2] = (UBYTE) BytesNeeded;
  3481.           ByteArray [3] = (UBYTE) (BytesNeeded >> 8);
  3482.           AmountToWrite = 4;
  3483.         }
  3484.         else /* Has to fit in 4 bytes. */
  3485.         {
  3486.           ByteArray [1] = 0xFF; /* Marks doubling of size extension. */
  3487.           ByteArray [2] = 0xFF; /* Marks redoubling of size extension. */
  3488.           ByteArray [3] = 0xFF;
  3489.           ByteArray [4] = (UBYTE) (BytesNeeded);
  3490.           ByteArray [5] = (UBYTE) (BytesNeeded >> 8);
  3491.           ByteArray [6] = (UBYTE) (BytesNeeded >> 16);
  3492.           ByteArray [7] = (UBYTE) (BytesNeeded >> 24);
  3493.           AmountToWrite = 8;
  3494.         }
  3495.       }
  3496.     }
  3497.  
  3498.     /* Write the header fields for the IntRep based number. */
  3499.  
  3500.     AmountWritten = (* CallBack) (PICBOP_WRITE,
  3501.     ByteArray, AmountToWrite, UserPntr);
  3502.     ByteCount += AmountWritten;
  3503.     if (AmountWritten != AmountToWrite)
  3504.       DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_WRITE_ERROR));
  3505.     else /* Write the body, the actual data bytes. */
  3506.     {
  3507.       ReturnCode = TRUE;  /* Assume success, errors now clear return code. */
  3508.  
  3509. #if _M68000 /* Motorola 68000 series CPUs uses MSB order. */
  3510.  
  3511.       /* Write out the body, swapping low and high bytes in each short.
  3512.          Use the ByteArray to buffer things a bit (assumes even size). */
  3513.  
  3514.       AmountToWrite = 0;
  3515.       NextShortPntr = AnIntRep->numberArray;
  3516.       while (BytesNeeded > 0)
  3517.       {
  3518.         CurrentShort = *NextShortPntr++;
  3519.         ByteArray [AmountToWrite++] = (UBYTE) CurrentShort;
  3520.         if (--BytesNeeded > 0)
  3521.         {
  3522.           ByteArray [AmountToWrite++] = (UBYTE) (CurrentShort >> 8);
  3523.           --BytesNeeded;
  3524.         }
  3525.  
  3526.         if (AmountToWrite >= sizeof (ByteArray) || BytesNeeded == 0)
  3527.         {
  3528.           AmountWritten = (* CallBack) (PICBOP_WRITE,
  3529.           ByteArray, AmountToWrite, UserPntr);
  3530.           ByteCount += AmountWritten;
  3531.           if (AmountWritten != AmountToWrite)
  3532.           {
  3533.             DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_WRITE_ERROR));
  3534.             ReturnCode = FALSE;
  3535.             break;
  3536.           }
  3537.           AmountToWrite = 0;
  3538.         }
  3539.       }
  3540.  
  3541. #else /* Just dump the data out directly, already in right byte order. */
  3542.  
  3543.       if ((AmountToWrite = BytesNeeded) > 0)
  3544.       {
  3545.         AmountWritten = (* CallBack) (PICBOP_WRITE,
  3546.         AnIntRep->numberArray, AmountToWrite, UserPntr);
  3547.         ByteCount += AmountWritten;
  3548.         if (AmountWritten != AmountToWrite)
  3549.         {
  3550.           DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_WRITE_ERROR));
  3551.           ReturnCode = FALSE;
  3552.         }
  3553.       }
  3554. #endif
  3555.     }
  3556.   }
  3557.   else /* Special code or NULL. */
  3558.   {
  3559.     AmountToWrite = 1;
  3560.     SpecialCode = IntoidToSpecialCode (AnIntoid);
  3561.     switch (SpecialCode)
  3562.     {
  3563.       case ISC_NOT_A_NUMBER:
  3564.         ByteArray [0] = 0x95;
  3565.         break;
  3566.  
  3567.       case ISC_POSITIVE_INFINITY:
  3568.         ByteArray [0] = 0x93;
  3569.         break;
  3570.  
  3571.       case ISC_NEGATIVE_INFINITY:
  3572.         ByteArray [0] = 0x94;
  3573.         break;
  3574.  
  3575.       default:
  3576.         ByteArray [0] = 0x92; /* Extended special code. */
  3577.         ByteArray [1] = 4; /* Noisy not-a-number. */
  3578.         AmountToWrite = 2;
  3579.         break;
  3580.     }
  3581.     AmountWritten = (* CallBack) (PICBOP_WRITE, ByteArray, AmountToWrite,
  3582.     UserPntr);
  3583.     ByteCount += AmountWritten;
  3584.     if (AmountWritten != AmountToWrite)
  3585.       DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_PI_WRITE_ERROR));
  3586.     else /* Success */
  3587.       ReturnCode = TRUE;
  3588.   }
  3589.  
  3590.   /* Set return values. */
  3591.  
  3592.   if (BytesWrittenPntr != NULL)
  3593.     *BytesWrittenPntr = ByteCount;
  3594.  
  3595.   return ReturnCode;
  3596. }
  3597.  
  3598.  
  3599.  
  3600. /****** intoids.library/IntoidToPortableIntViaBuffer ************************
  3601. *
  3602. *   NAME
  3603. *       IntoidToPortableIntViaBuffer -- Converts Intoid to portable int.
  3604. *
  3605. *   SYNOPSIS
  3606. *       Success = IntoidToPortableIntViaBuffer
  3607. *                 ( AnIntoid, BytesWrittenPntr, Buffer, BufferSize )
  3608. *       D0          D0        A0                A1      D1
  3609. *
  3610. *       BOOL IntoidToPortableIntViaBuffer( Intoid, ULONG *, APTR, ULONG );
  3611. *
  3612. *   FUNCTION
  3613. *       Writes the AGMS Portable Integer binary format equivalent of the
  3614. *       Intoid (big integer) to a buffer.
  3615. *
  3616. *   INPUTS
  3617. *       AnIntoid - the arbitrarily big integer to be converted.
  3618. *       BytesWrittenPntr - points to a ULONG that will be set to the number
  3619. *           of bytes written, specify NULL if you aren't using this feature.
  3620. *       Buffer - points to an area of memory where the portable integer will
  3621. *           be written to.
  3622. *       BufferSize - amount of space in the buffer.  Has to be at least
  3623. *           enough for the entire portable integer, or you get a partial
  3624. *           portable integer in the buffer and BytesWritten equal to
  3625. *           BufferSize.
  3626. *
  3627. *   RESULT
  3628. *       Success - returns TRUE (1) if successful, FALSE (0) if it fails.
  3629. *       BytesWrittenPntr - the pointed to ULONG is set to the number of
  3630. *           bytes actually written.  If you have an IO error then this
  3631. *           will be less than the actual size (see PortableIntSizeOfIntoid())
  3632. *           for the number.
  3633. *
  3634. *   SEE ALSO
  3635. *       PortableIntSizeOfIntoid(), IntoidToPortableIntViaCallBack().
  3636. *
  3637. *****************************************************************************
  3638. */
  3639.  
  3640. BOOL LIBFUNC IntoidToPortableIntViaBuffer (
  3641.   REGD0 Intoid AnIntoid,
  3642.   REGA0 ULONG *BytesWrittenPntr,
  3643.   REGA1 APTR Buffer,
  3644.   REGD1 ULONG BufferSize)
  3645. {
  3646.   BufferStreamRecord  BufferAsStream;
  3647.  
  3648.   BufferAsStream.current = BufferAsStream.start = Buffer;
  3649.   BufferAsStream.end = (UBYTE *) Buffer + BufferSize;
  3650.  
  3651.   return IntoidToPortableIntViaCallBack (AnIntoid, BytesWrittenPntr,
  3652.   BufferAsStreamCallBack, &BufferAsStream);
  3653. }
  3654.  
  3655.  
  3656.  
  3657. /******************************************************************************
  3658.  * This callback function does nothing, always succeeding in reading or
  3659.  * writing or seeking.  It is used for finding the size of an Intoid as a
  3660.  * portable integer by writing the portable integer to nowhere.
  3661.  */
  3662.  
  3663. LONG STACKCALL DoNothingStreamCallBack (ULONG Operation, APTR Buffer,
  3664. LONG Amount, APTR UserPntr)
  3665. {
  3666.   switch (Operation)
  3667.   {
  3668.     case PICBOP_READ:
  3669.       return Amount;
  3670.  
  3671.     case PICBOP_SEEK:
  3672.       return 0;  /* New seek position is always zero. */
  3673.  
  3674.     case PICBOP_WRITE:
  3675.       return Amount;
  3676.   }
  3677.  
  3678.   return -2; /* Unimplemented operation. */
  3679. }
  3680.  
  3681.  
  3682.  
  3683. /****** intoids.library/PortableIntSizeOfIntoid *****************************
  3684. *
  3685. *   NAME
  3686. *       PortableIntSizeOfIntoid -- Find Intoid size in portable int format.
  3687. *
  3688. *   SYNOPSIS
  3689. *       Length = PortableIntSizeOfIntoid( AnIntoid )
  3690. *       D0                                D0
  3691. *
  3692. *       ULONG PortableIntSizeOfIntoid( Intoid );
  3693. *
  3694. *   FUNCTION
  3695. *       Finds the byte size of an Intoid when expressed in AGMS Portable
  3696. *       Integer format.
  3697. *
  3698. *   INPUTS
  3699. *       AnIntoid - the big integer you want to find the formatted size of.
  3700. *
  3701. *   RESULT
  3702. *       Length - the number of bytes it would take for the AGMS Portable
  3703. *           Integer binary format equivalent of AnIntoid.
  3704. *
  3705. *****************************************************************************
  3706. */
  3707.  
  3708. ULONG LIBFUNC PortableIntSizeOfIntoid (REGA0 Intoid AnIntoid)
  3709. {
  3710.   ULONG ByteCount;
  3711.  
  3712.   IntoidToPortableIntViaCallBack (AnIntoid, &ByteCount,
  3713.   DoNothingStreamCallBack, NULL);
  3714.  
  3715.   return ByteCount;
  3716. }
  3717.  
  3718.  
  3719.  
  3720. /****** intoids.library/IntoidToAscii ***************************************
  3721. *
  3722. *   NAME
  3723. *       IntoidToAscii -- Converts an Intoid into printable ASCII text.
  3724. *
  3725. *   SYNOPSIS
  3726. *       RequiredLength = IntoidToAscii( IntegerA, Buffer, BufferLength, Base)
  3727. *       D0                              A0        A1      D0            D1
  3728. *
  3729. *       LONG IntoidToAscii( Intoid, STRPTR, LONG, UWORD );
  3730. *
  3731. *   FUNCTION
  3732. *       Converts the Intoid to a readable string number in the given base.
  3733. *       Also can output special strings for not-a-number and infinities, and
  3734. *       various error messages if something goes wrong during the conversion.
  3735. *
  3736. *   INPUTS
  3737. *       IntegerA - any Intoid.
  3738. *       Buffer - points to a user provided buffer that will be filled with
  3739. *           the NUL terminated string ASCII text equivalent of IntegerA.
  3740. *           This variable can be NULL (useful if you just want an estimate of
  3741. *           how long the string would be).
  3742. *       BufferLength - how many bytes are in Buffer.  Can be zero.
  3743. *       Base - what number system to use for the conversion.  Can be from 2
  3744. *           to 36 (because it uses the 26 lower case letters and '0' to '9'
  3745. *           for the output digits).
  3746. *
  3747. *   RESULT
  3748. *       RequiredLength - returns the number of characters plus one (for the
  3749. *           NUL at the end of the string) required to represent the number
  3750. *           (may be more than BufferLength).
  3751. *       Buffer - filled with the number, or with '*' characters if it isn't
  3752. *           big enough to hold the number.
  3753. *
  3754. *   NOTES
  3755. *       Uses about 1K of the caller's stack space.
  3756. *
  3757. *   BUGS
  3758. *       Numbers can only be converted if they are less than
  3759. *       MAX_INTOID_ASCII_DIGITS long.  This is because a reversed number is
  3760. *       built up in a buffer this big on the caller's stack (thus you need
  3761. *       about 1K of stack when calling this function).  If a number is too
  3762. *       big, you will get an error message instead of the number.
  3763. *
  3764. *****************************************************************************
  3765. */
  3766.  
  3767. LONG LIBFUNC IntoidToAscii (REGA0 Intoid IntegerA, REGA1 STRPTR Buffer,
  3768. REGD0 LONG BufferLength, REGD1 UWORD Base)
  3769. {
  3770.   char         *NextDigitPntr;
  3771.   BOOL          Positive;
  3772.   long          RequiredLength;
  3773.   char          ReversedNumber [MAX_INTOID_ASCII_DIGITS];
  3774.   char         *EndOfReversedNumber;
  3775.  
  3776.   if (Base < 2 || Base > 36)
  3777.   {
  3778.     DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_BAD_INPUT_PARMS));
  3779.     return 0; /* Avoid infinite loops and divide by zero and bad characters. */
  3780.   }
  3781.  
  3782.   if (Buffer == NULL)
  3783.     BufferLength = 0; /* Fine, we will just tell them how many digits. */
  3784.  
  3785.   NextDigitPntr = ReversedNumber;
  3786.   EndOfReversedNumber = ReversedNumber + sizeof (ReversedNumber);
  3787.   Positive = TRUE;
  3788.  
  3789.   if (IntoidIsSmallInt (IntegerA))
  3790.   {
  3791.     unsigned long rem;
  3792.     long SmallInt = IntoidToSmallInt (IntegerA);
  3793.     if (SmallInt < 0)
  3794.     {
  3795.       SmallInt = -SmallInt;
  3796.       Positive = FALSE;
  3797.     }
  3798.     rem = SmallInt;
  3799.     while (rem != 0)
  3800.     {
  3801.       char ch;
  3802. #if _AMIGA && __SASC
  3803.       rem = UDivMod32 (rem, (unsigned long) Base);
  3804.       ch = getreg (REG_D1);
  3805. #else
  3806.       ch = rem % Base;
  3807.       rem /= Base;
  3808. #endif
  3809.       if (ch >= 10)
  3810.         ch += 'a' - 10;
  3811.       else
  3812.         ch += '0';
  3813.       *NextDigitPntr++ = ch;
  3814.     }
  3815.   }
  3816.   else if (IntoidIsIntRep (IntegerA))
  3817.   {
  3818.     IntRepPointer IntRepA = (IntoidAsPointer) IntegerA;
  3819.     IntRepPointer TempIntRep;
  3820.     TempIntRep = Icopy (NULL, IntRepA);
  3821.     if (TempIntRep == NULL)
  3822.     {
  3823.       strcpy (ReversedNumber,
  3824.       GetIntoidsMessage (MSG_INTOIDS_PRINTING_OUT_OF_MEMORY));
  3825.       strrev (ReversedNumber);
  3826.       NextDigitPntr = ReversedNumber + strlen (ReversedNumber);
  3827.     }
  3828.     else /* Not out of memory. */
  3829.     {
  3830.       /* split division by base into two parts:
  3831.          first divide by biggest power of base that fits in an unsigned short,
  3832.          then use straight signed div/mods from there. */
  3833.  
  3834.       /* find power */
  3835.       int bpower = 1;
  3836.       unsigned short b = Base;
  3837.       unsigned short maxb = I_MAXNUM / Base;
  3838.       while (b < maxb)
  3839.       {
  3840.         b *= Base;
  3841.         ++bpower;
  3842.       }
  3843.  
  3844.       Positive = IntRepA->positiveSign;
  3845.       for(;;)
  3846.       {
  3847.         unsigned short rem = unscale(TempIntRep->numberArray,
  3848.         TempIntRep->currentLength, b, TempIntRep->numberArray);
  3849.         Icheck(TempIntRep);
  3850.         if (TempIntRep->currentLength == 0)
  3851.         {
  3852.           while (rem != 0)
  3853.           {
  3854.             char ch;
  3855.             unsigned short u;
  3856.             u = rem / Base;
  3857.             ch = rem - u * Base;
  3858.             rem = u;
  3859.             if (ch >= 10)
  3860.               ch += 'a' - 10;
  3861.             else
  3862.               ch += '0';
  3863.             if (NextDigitPntr < EndOfReversedNumber)
  3864.               *NextDigitPntr = ch;
  3865.             ++NextDigitPntr;
  3866.           }
  3867.           Idelete (TempIntRep);
  3868.           break;
  3869.         }
  3870.         else
  3871.         {
  3872.           int i;
  3873.           for (i = 0; i < bpower; ++i)
  3874.           {
  3875.             char ch;
  3876.             unsigned short u;
  3877.             u = rem / Base;
  3878.             ch = rem - u * Base;
  3879.             rem = u;
  3880.             if (ch >= 10)
  3881.               ch += 'a' - 10;
  3882.             else
  3883.               ch += '0';
  3884.             if (NextDigitPntr < EndOfReversedNumber)
  3885.               *NextDigitPntr = ch;
  3886.             ++NextDigitPntr;
  3887.           }
  3888.         }
  3889.       }
  3890.     }
  3891.   }
  3892.   else /* Must be a specially encoded meaning. */
  3893.   {
  3894.     switch (IntoidToSpecialCode (IntegerA))
  3895.     {
  3896.       case ISC_NEGATIVE_INFINITY:
  3897.         Positive = FALSE;
  3898.       case ISC_POSITIVE_INFINITY:
  3899.         strcpy (ReversedNumber, GetIntoidsMessage (MSG_INTOIDS_INFINITY));
  3900.         break;
  3901.  
  3902.       case ISC_NOT_A_NUMBER:
  3903.       default:
  3904.         strcpy (ReversedNumber, GetIntoidsMessage (MSG_INTOIDS_NOT_A_NUMBER));
  3905.         break;
  3906.     }
  3907.     strrev (ReversedNumber);
  3908.     NextDigitPntr = ReversedNumber + strlen (ReversedNumber);
  3909.   }
  3910.  
  3911.   if (NextDigitPntr == ReversedNumber)
  3912.     *NextDigitPntr++ = '0';  /* Empty string means zero. */
  3913.  
  3914.   if (NextDigitPntr > EndOfReversedNumber)
  3915.   {
  3916.     strcpy (ReversedNumber,
  3917.     GetIntoidsMessage (MSG_INTOIDS_NUMBER_TOO_BIG_TO_PRINT));
  3918.     strrev (ReversedNumber);
  3919.     NextDigitPntr = ReversedNumber + strlen (ReversedNumber);
  3920.   }
  3921.  
  3922.   /* Now have the number's digits.  Find out if there is space for it. */
  3923.  
  3924.   RequiredLength = (NextDigitPntr - ReversedNumber) + 1 /* For NUL */;
  3925.   if (!Positive) RequiredLength++;
  3926.  
  3927.   if (RequiredLength > BufferLength)
  3928.   {
  3929.     /* Number too big, fill buffer with '*' characters. */
  3930.  
  3931.     while (BufferLength > 1)
  3932.     {
  3933.       *Buffer++ = '*';
  3934.       --BufferLength;
  3935.     }
  3936.   }
  3937.   else
  3938.   {
  3939.     /* Reverse copy the string to the output buffer.  Put the minus sign in
  3940.        front if it is negative. */
  3941.  
  3942.     if (!Positive)
  3943.       *Buffer++ = '-';
  3944.  
  3945.     /* Copy the digits (or error message) over. */
  3946.  
  3947.     while (--NextDigitPntr >= ReversedNumber)
  3948.       *Buffer++ = *NextDigitPntr;
  3949.   }
  3950.  
  3951.   if (BufferLength > 0)
  3952.     *Buffer = 0; /* End of string. */
  3953.  
  3954.   return RequiredLength;
  3955. }
  3956.  
  3957.  
  3958.  
  3959. /****** intoids.library/AsciiToIntoid ***************************************
  3960. *
  3961. *   NAME
  3962. *       AsciiToIntoid -- Convert an ASCII string to an Intoid.
  3963. *
  3964. *   SYNOPSIS
  3965. *       New = AsciiToIntoid( Buffer, NextCharacterPntrPntr, Base, RecycleMe )
  3966. *       D0                   A0      A1                     D0    D1
  3967. *
  3968. *       Intoid AsciiToIntoid( STRPTR, char **, UWORD, Intoid );
  3969. *
  3970. *   FUNCTION
  3971. *       Converts a string to a number using the given base, much like
  3972. *       the standard C function strtol.  It recognizes numbers consisting of
  3973. *       some leading space ((spaces or tabs) or international isspace() if
  3974. *       locale.library is available), an optional sign, an optional base
  3975. *       indicator if Base is zero, and finally a bunch of digits (which can
  3976. *       also be the special current language specific strings for infinity or
  3977. *       not-a-number).
  3978. *
  3979. *   INPUTS
  3980. *       Buffer - points to a buffer containing the NUL terminated string to
  3981. *           be converted.
  3982. *       NextCharacterPntrPntr - points to a user's pointer variable, or NULL
  3983. *           if you don't want to use it.  The user's pointer variable will be
  3984. *           set to point to the character after the last one that was part of
  3985. *           the number (or set to NULL if a bad error happened).
  3986. *       Base - which number system to use.  Base can be from 2 to 36.  A Base
  3987. *           of 0 can be used for automatic base determination (if the number
  3988. *           starts with "0x" then it is treated as base 16, if it starts with
  3989. *           "0" then base 8 is used, otherwise it defaults to base 10).
  3990. *       RecycleMe - an old Intoid you want to deallocate, or NULL.
  3991. *
  3992. *   RESULT
  3993. *       New - a newly allocated Intoid with the integer equivalent to the
  3994. *             string in Buffer.  NULL if out of memory or some other error
  3995. *             happens (or if the string says not-a-number).
  3996. *       NextCharacterPntrPntr - sets user's pointer to just after the number.
  3997. *
  3998. *   NOTES
  3999. *       The special strings for infinity and not-a-number are language
  4000. *       dependent.  If you read a file written in English on a French
  4001. *       computer, it won't understand the special infinity values.  Instead,
  4002. *       you should use the portable binary formatting functions.
  4003. *
  4004. *   SEE ALSO
  4005. *       GetIntoidsMessage(), MSG_INTOIDS_NOT_A_NUMBER, MSG_INTOIDS_INFINITY.
  4006. *
  4007. *****************************************************************************
  4008. */
  4009.  
  4010. Intoid LIBFUNC AsciiToIntoid (REGA0 STRPTR Buffer,
  4011. REGA1 char **NextCharacterPntrPntr, REGD0 UWORD Base,
  4012. REGD1 Intoid RecycleMe)
  4013. {
  4014.   const char     *CharPntr;
  4015.   char            Digit;
  4016.   const char     *DigitsStart;
  4017.   char            Letter;
  4018.   int             Log2OfBase;
  4019.   unsigned long   NewLength;
  4020.   const char     *NumberEnd;
  4021.   const char     *NumberStart;
  4022.   BOOL            IsPositive;
  4023.   Intoid          ReturnValue;
  4024.   long            TempLong;
  4025.  
  4026.   if (NextCharacterPntrPntr != NULL)
  4027.     *NextCharacterPntrPntr = NULL; /* In case of errors. */
  4028.  
  4029.   if (Buffer == NULL || Base == 1 || Base > 36)
  4030.   {
  4031.     DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_BAD_INPUT_PARMS));
  4032.     return NULL; /* Can't do it. */
  4033.   }
  4034.  
  4035.   /* Skip leading space to get to the start of
  4036.      the number (may be a sign or digit). */
  4037.  
  4038.   NumberEnd = NULL; /* This only gets set when we have an answer. */
  4039.   NumberStart = Buffer;
  4040.   while (MyIsSpace ((unsigned long) *NumberStart))
  4041.     ++NumberStart;
  4042.  
  4043.   /* Go past the sign to get to the digits. */
  4044.  
  4045.   IsPositive = TRUE;
  4046.   DigitsStart = NumberStart;
  4047.   if (*DigitsStart == '-')
  4048.   {
  4049.     ++DigitsStart;
  4050.     IsPositive = FALSE;
  4051.   }
  4052.   else if (*DigitsStart == '+')
  4053.     ++DigitsStart;
  4054.  
  4055.   /* Check for magic base indicators, only if Base is zero. */
  4056.  
  4057.   if (Base == 0)
  4058.   {
  4059.     if (*DigitsStart == '0') /* Number starts with a leading zero. */
  4060.     {
  4061.       ++DigitsStart;  /* Skip leading zero. */
  4062.       if (*DigitsStart == 'x' || *DigitsStart == 'X')
  4063.       {
  4064.         Base = 16;
  4065.         ++DigitsStart; /* Skip over the x. */
  4066.       }
  4067.       else
  4068.         Base = 8;
  4069.     }
  4070.     else /* The default base. */
  4071.       Base = 10;
  4072.   }
  4073.  
  4074.   /* Check for infinity or not a number strings.  Use the utility.library
  4075.      international string comparison functions. */
  4076.  
  4077.   CharPntr = GetIntoidsMessage (MSG_INTOIDS_NOT_A_NUMBER);
  4078.   if (Strnicmp ((STRPTR) CharPntr, (STRPTR) DigitsStart,
  4079.   (long) strlen (CharPntr)) == 0)
  4080.   {
  4081.     NumberEnd = DigitsStart + strlen (CharPntr);
  4082.     ReturnValue = NULL; /* Not a number. */
  4083.   }
  4084.   else
  4085.   {
  4086.     CharPntr = GetIntoidsMessage (MSG_INTOIDS_INFINITY);
  4087.     if (Strnicmp ((STRPTR) CharPntr, (STRPTR) DigitsStart,
  4088.     (long) strlen (CharPntr)) == 0)
  4089.     {
  4090.       NumberEnd = DigitsStart + strlen (CharPntr);
  4091.       if (IsPositive)
  4092.         ReturnValue = SpecialCodeToIntoid (ISC_POSITIVE_INFINITY);
  4093.       else
  4094.         ReturnValue = SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY);
  4095.     }
  4096.   }
  4097.  
  4098.   if (NumberEnd == NULL)
  4099.   {
  4100.     /* Find number of bits in the base, each digit in the
  4101.        input can have at most this many bits in the number. */
  4102.  
  4103.     Log2OfBase = 0;
  4104.     TempLong = Base;
  4105.     while (TempLong != 0)
  4106.     {
  4107.       TempLong >>= 1;
  4108.       Log2OfBase++;
  4109.     }
  4110.  
  4111.     /* Find the end of the number, and count digits. */
  4112.  
  4113.     CharPntr = DigitsStart;
  4114.     while ((Letter = *CharPntr) != 0)
  4115.     {
  4116.       if (Letter >= '0' && Letter <= '9') Digit = Letter - '0';
  4117.       else if (Letter >= 'a' && Letter <= 'z') Digit = Letter - 'a' + 10;
  4118.       else if (Letter >= 'A' && Letter <= 'Z') Digit = Letter - 'A' + 10;
  4119.       else break;
  4120.       if (Digit >= Base) break;
  4121.       ++CharPntr;
  4122.     }
  4123.     NumberEnd = CharPntr;
  4124.  
  4125.     /* Now find the total number of bits that we might need.  The actual
  4126.        number may be smaller if there are leading zeroes. */
  4127.  
  4128.     NewLength = (NumberEnd - DigitsStart) * (long) Log2OfBase;
  4129.  
  4130.     /* If it doesn't fit in a small integer Intoid... */
  4131.  
  4132.     if (NewLength > CHAR_PER_LONG * CHAR_BIT - 2)
  4133.     {
  4134.       /* May need a full IntRep, allocate one then reduce later. */
  4135.  
  4136.       NewLength = NewLength / I_SHIFT + 1;  /* Number of shorts we need. */
  4137.       ReturnValue = ResizeIntoid (RecycleMe, NewLength, TRUE /* Zero it */);
  4138.       RecycleMe = NULL;  /* We have used it. */
  4139.  
  4140.       /* Reading in a large number into an IntRep.  Stop when an error
  4141.          happens or if it already happened (out of memory). */
  4142.  
  4143.       CharPntr = DigitsStart;
  4144.       while ((Letter = *CharPntr) != 0 && ReturnValue != NULL)
  4145.       {
  4146.         if (Letter >= '0' && Letter <= '9') Digit = Letter - '0';
  4147.         else if (Letter >= 'a' && Letter <= 'z') Digit = Letter - 'a' + 10;
  4148.         else if (Letter >= 'A' && Letter <= 'Z') Digit = Letter - 'A' + 10;
  4149.         else break;
  4150.         if (Digit >= Base) break;
  4151.  
  4152.         ReturnValue = MultiplyLongAndIntRep ((long) Base, ReturnValue,
  4153.         ReturnValue);
  4154.  
  4155.         ReturnValue = AddLongAndIntRep ((long) Digit, ReturnValue,
  4156.         FALSE /* don't negate it */, ReturnValue);
  4157.  
  4158.         ++CharPntr;
  4159.       }
  4160.       if (IntoidIsIntRep (ReturnValue))
  4161.       {
  4162.         ((IntoidAsPointer) ReturnValue)->positiveSign = IsPositive;
  4163.         ReturnValue = NormalizeIntoid (ReturnValue);
  4164.       }
  4165.       else /* Something went wrong.  Probably out of memory. */
  4166.       {
  4167.         FreeIntoid (ReturnValue);
  4168.         ReturnValue = NULL;
  4169.       }
  4170.     }
  4171.     else /* Number will fit in a small integer intoid. */
  4172.     {
  4173.       TempLong = 0;
  4174.       CharPntr = DigitsStart;
  4175.       while ((Letter = *CharPntr) != 0)
  4176.       {
  4177.         if (Letter >= '0' && Letter <= '9') Digit = Letter - '0';
  4178.         else if (Letter >= 'a' && Letter <= 'z') Digit = Letter - 'a' + 10;
  4179.         else if (Letter >= 'A' && Letter <= 'Z') Digit = Letter - 'A' + 10;
  4180.         else break;
  4181.         if (Digit >= Base) break;
  4182.         TempLong = TempLong * Base + Digit;
  4183.         ++CharPntr;
  4184.       }
  4185.       if (!IsPositive)
  4186.         TempLong = -TempLong;
  4187.       ReturnValue = SmallIntToIntoid (TempLong);
  4188.     }
  4189.   }
  4190.  
  4191.   FreeIntoid (RecycleMe);  /* Frees it if it wasn't used up. */
  4192.  
  4193.   if (NextCharacterPntrPntr != NULL)
  4194.     *NextCharacterPntrPntr = (char *) NumberEnd;
  4195.  
  4196.   return ReturnValue;
  4197. }
  4198.  
  4199.  
  4200.  
  4201. /****** intoids.library/CopyIntoid ******************************************
  4202. *
  4203. *   NAME
  4204. *       CopyIntoid -- Allocates a copy of an Intoid.
  4205. *
  4206. *   SYNOPSIS
  4207. *       NewIntoid = CopyIntoid( IntegerA, RecycleMe )
  4208. *       D0                      D0        D1
  4209. *
  4210. *       Intoid CopyIntoid( Intoid, Intoid );
  4211. *
  4212. *   FUNCTION
  4213. *       Allocates memory (if needed) and fills it with a copy of IntegerA.
  4214. *
  4215. *   INPUTS
  4216. *       IntegerA - the Integer value you want to copy.
  4217. *       RecycleMe - an old Intoid you want to deallocate, or NULL.
  4218. *
  4219. *   RESULT
  4220. *       NewIntoid - A copy of IntegerA or NULL if out of memory.
  4221. *
  4222. *****************************************************************************
  4223. */
  4224.  
  4225. Intoid LIBFUNC CopyIntoid (REGD0 Intoid IntegerA, REGD1 Intoid RecycleMe)
  4226. {
  4227.   Intoid        NewIntoid;
  4228.   IntRepPointer NewRep;
  4229.  
  4230.   if (IntoidIsIntRep (IntegerA))
  4231.   {
  4232.     NewRep = Icopy (IntoidIsIntRep (RecycleMe) ?
  4233.     (IntoidAsPointer) RecycleMe : NULL,
  4234.     (IntoidAsPointer) IntegerA);
  4235.  
  4236.     if (NewRep != NULL)
  4237.       Icheck (NewRep);
  4238.  
  4239.     NewIntoid = NormalizeIntoid ((Intoid) NewRep);
  4240.   }
  4241.   else /* A small integer or special code.  No auxiliary data. */
  4242.   {
  4243.     NewIntoid = IntegerA;
  4244.     FreeIntoid (RecycleMe);
  4245.   }
  4246.  
  4247.   return NewIntoid;
  4248. }
  4249.  
  4250.  
  4251.  
  4252. /****** intoids.library/AddIntoids ******************************************
  4253. *
  4254. *   NAME
  4255. *       AddIntoids -- Adds two Intoids.
  4256. *
  4257. *   SYNOPSIS
  4258. *       NewIntoid = AddIntoids( IntegerA, IntegerB, RecycleMe )
  4259. *       D0                      D0        D1        A0
  4260. *
  4261. *       Intoid AddIntoids( Intoid, Intoid, Intoid );
  4262. *
  4263. *   FUNCTION
  4264. *       Adds two intoids and returns a new one with the sum.
  4265. *
  4266. *   INPUTS
  4267. *       IntegerA - one value to be added.
  4268. *       IntegerB - the other value to be added.
  4269. *       RecycleMe - an old Intoid you want to deallocate, or NULL.
  4270. *
  4271. *   RESULT
  4272. *       NewIntoid - newly allocated Intoid with a value of (A + B), or NULL
  4273. *           if out of memory.
  4274. *
  4275. *****************************************************************************
  4276. */
  4277.  
  4278. Intoid LIBFUNC AddIntoids (REGD0 Intoid IntegerA, REGD1 Intoid IntegerB,
  4279. REGA0 Intoid RecycleMe)
  4280. {
  4281.   /* Most frequent case is two small integer Intoids.  Just convert to longs
  4282.      and add.  They shouldn't overflow in the long addition, though the result
  4283.      may be too big for a small integer (LongToIntoid will fix that). */
  4284.  
  4285.   if (IntoidIsSmallInt (IntegerA) && IntoidIsSmallInt (IntegerB))
  4286.     return LongToIntoid (IntoidToSmallInt (IntegerA) +
  4287.     IntoidToSmallInt (IntegerB), RecycleMe);
  4288.  
  4289.   /* If adding zero or not-a-number, return a copy of the other number. */
  4290.  
  4291.   if (IntegerA == NULL || IntegerA == SmallIntToIntoid (0))
  4292.     return CopyIntoid (IntegerB, RecycleMe);
  4293.  
  4294.   if (IntegerB == NULL || IntegerB == SmallIntToIntoid (0))
  4295.     return CopyIntoid (IntegerA, RecycleMe);
  4296.  
  4297.   /* Check for adding infinity.  The result is usually infinity. */
  4298.  
  4299.   if (IntegerA == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
  4300.   {
  4301.     FreeIntoid (RecycleMe);
  4302.     if (IntegerB == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
  4303.       return SmallIntToIntoid (0); /* Well... */
  4304.     return SpecialCodeToIntoid (ISC_POSITIVE_INFINITY);
  4305.   }
  4306.  
  4307.   if (IntegerB == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
  4308.   {
  4309.     FreeIntoid (RecycleMe);
  4310.     if (IntegerA == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
  4311.       return SmallIntToIntoid (0); /* Well... */
  4312.     return SpecialCodeToIntoid (ISC_POSITIVE_INFINITY);
  4313.   }
  4314.  
  4315.   if (IntegerA == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
  4316.   {
  4317.     FreeIntoid (RecycleMe);
  4318.     if (IntegerB == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
  4319.       return SmallIntToIntoid (0); /* Well... */
  4320.     return SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY);
  4321.   }
  4322.  
  4323.   if (IntegerB == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
  4324.   {
  4325.     FreeIntoid (RecycleMe);
  4326.     if (IntegerA == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
  4327.       return SmallIntToIntoid (0); /* Well... */
  4328.     return SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY);
  4329.   }
  4330.  
  4331.   if (IntoidIsSpecialCode (IntegerA))
  4332.   {
  4333.     FreeIntoid (RecycleMe);
  4334.     return IntegerA;
  4335.   }
  4336.  
  4337.   if (IntoidIsSpecialCode (IntegerB))
  4338.   {
  4339.     FreeIntoid (RecycleMe);
  4340.     return IntegerB;
  4341.   }
  4342.  
  4343.   /* Check for numbers that fit in a long so we can do a simpler long/intrep
  4344.      addition.  Already know that not both are small integers. */
  4345.  
  4346.   if (IntoidIsSmallInt (IntegerA))
  4347.     return NormalizeIntoid (AddLongAndIntRep (IntoidToSmallInt (IntegerA),
  4348.     IntegerB, FALSE, RecycleMe));
  4349.  
  4350.   if (IntoidIsSmallInt (IntegerB))
  4351.     return NormalizeIntoid (AddLongAndIntRep (IntoidToSmallInt (IntegerB),
  4352.     IntegerA, FALSE, RecycleMe));
  4353.  
  4354.   /* Ok, now adding two Intoids which are IntReps. */
  4355.  
  4356.   return NormalizeIntoid (AddIntRepAndIntRep (IntegerA, FALSE,
  4357.   IntegerB, FALSE, RecycleMe));
  4358. }
  4359.  
  4360.  
  4361.  
  4362. /****** intoids.library/NegateIntoid ****************************************
  4363. *
  4364. *   NAME
  4365. *       NegateIntoid -- Returns the negative of an intoid.
  4366. *
  4367. *   SYNOPSIS
  4368. *       NewIntoid = NegateIntoid( IntegerA, RecycleMe )
  4369. *       D0                        D0        D1
  4370. *
  4371. *       Intoid NegateIntoid( Intoid, Intoid );
  4372. *
  4373. *   FUNCTION
  4374. *       Computes (0 - IntegerA).
  4375. *
  4376. *   INPUTS
  4377. *       IntegerA - the value you want to get the negative of.
  4378. *       RecycleMe - an old Intoid you want to deallocate, or NULL.
  4379. *
  4380. *   RESULT
  4381. *       NewIntoid - newly allocated Intoid containing (0 - IntegerA), or NULL
  4382. *           if out of memory.
  4383. *
  4384. *****************************************************************************
  4385. */
  4386.  
  4387. Intoid LIBFUNC NegateIntoid (REGD0 Intoid IntegerA, REGD1 Intoid RecycleMe)
  4388. {
  4389.   Intoid        Negated;
  4390.   IntRepPointer NegatedRep;
  4391.  
  4392.   Negated = CopyIntoid (IntegerA, RecycleMe);
  4393.  
  4394.   if (IntoidIsSmallInt (Negated))
  4395.   {
  4396.     Negated = LongToIntoid (-IntoidToSmallInt (Negated), NULL);
  4397.   }
  4398.   else if (IntoidIsIntRep (Negated))
  4399.   {
  4400.     NegatedRep = (IntoidAsPointer) Negated;
  4401.     NegatedRep->positiveSign = !NegatedRep->positiveSign;
  4402.     /* Don't bother converting -0x40000000 to small integer form. */
  4403.   }
  4404.   else /* A special code.  Only infinities change sign. */
  4405.   {
  4406.     if (Negated == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
  4407.       Negated = SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY);
  4408.     else if (Negated == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
  4409.       Negated = SpecialCodeToIntoid (ISC_POSITIVE_INFINITY);
  4410.   }
  4411.  
  4412.   return Negated;
  4413. }
  4414.  
  4415.  
  4416.  
  4417. /****** intoids.library/AbsoluteIntoid **************************************
  4418. *
  4419. *   NAME
  4420. *       AbsoluteIntoid -- Computes absolute value of an Intoid.
  4421. *
  4422. *   SYNOPSIS
  4423. *       NewIntoid = AbsoluteIntoid( IntegerA, RecycleMe )
  4424. *       D0                          D0        D1
  4425. *
  4426. *       Intoid AbsoluteIntoid( Intoid, Intoid );
  4427. *
  4428. *   FUNCTION
  4429. *       Computes the absolute value of an Intoid.
  4430. *
  4431. *   INPUTS
  4432. *       IntegerA - the value you want to get the negative of.
  4433. *       RecycleMe - an old Intoid you want to deallocate, or NULL.
  4434. *
  4435. *   RESULT
  4436. *       NewIntoid - newly allocated Intoid containing a copy of IntegerA if
  4437. *           IntegerA was positive, or the negative of IntegerA if it was
  4438. *           originally negative (the negative of a negative is positive), or
  4439. *           NULL if out of memory.
  4440. *
  4441. *****************************************************************************
  4442. */
  4443.  
  4444. Intoid LIBFUNC AbsoluteIntoid (REGD0 Intoid IntegerA,
  4445. REGD1 Intoid RecycleMe)
  4446. {
  4447.   if (SignOfIntoid (IntegerA) < 0)
  4448.     return NegateIntoid (IntegerA, RecycleMe);
  4449.  
  4450.   return CopyIntoid (IntegerA, RecycleMe);
  4451. }
  4452.  
  4453.  
  4454.  
  4455. /****** intoids.library/SubtractIntoids *************************************
  4456. *
  4457. *   NAME
  4458. *       SubtractIntoids -- Computes value of one Intoid minus another.
  4459. *
  4460. *   SYNOPSIS
  4461. *       NewIntoid = SubtractIntoids( IntegerA, IntegerB, RecycleMe )
  4462. *       D0                           D0        D1        A0
  4463. *
  4464. *       Intoid SubtractIntoids( Intoid, Intoid, Intoid );
  4465. *
  4466. *   FUNCTION
  4467. *       Does subtraction, IntegerA - IntegerB.
  4468. *
  4469. *   INPUTS
  4470. *       IntegerA - one input value.
  4471. *       IntegerB - the other input value.
  4472. *       RecycleMe - an old Intoid you want to deallocate, or NULL.
  4473. *
  4474. *   RESULT
  4475. *       NewIntoid - newly allocated Intoid containing the value of
  4476. *           (IntegerA - IntegerB), or NULL if out of memory.
  4477. *
  4478. *****************************************************************************
  4479. */
  4480.  
  4481. Intoid LIBFUNC SubtractIntoids (REGD0 Intoid IntegerA, REGD1 Intoid IntegerB,
  4482. REGA0 Intoid RecycleMe)
  4483. {
  4484.   /* Most frequent case is two small integer Intoids.  Just convert to longs
  4485.      and subtract.  They shouldn't overflow in the long addition, though the
  4486.      result may be too big for a small integer (LongToIntoid will fix that). */
  4487.  
  4488.   if (IntoidIsSmallInt (IntegerA) && IntoidIsSmallInt (IntegerB))
  4489.     return LongToIntoid (IntoidToSmallInt (IntegerA) -
  4490.     IntoidToSmallInt (IntegerB), RecycleMe);
  4491.  
  4492.   /* If subtracting zero or not-a-number, return a copy of the other number,
  4493.      or a negative of it. */
  4494.  
  4495.   if (IntegerA == NULL || IntegerA == SmallIntToIntoid (0))
  4496.     return NegateIntoid (IntegerB, RecycleMe);
  4497.  
  4498.   if (IntegerB == NULL || IntegerB == SmallIntToIntoid (0))
  4499.     return CopyIntoid (IntegerA, RecycleMe);
  4500.  
  4501.   /* Check for subtracting infinity.  The result is usually infinity
  4502.      except when subtracting the same infinity, which has a zero
  4503.      result even though that probably isn't meaningful. */
  4504.  
  4505.   if (IntegerA == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
  4506.   {
  4507.     FreeIntoid (RecycleMe);
  4508.     if (IntegerB == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
  4509.       return SmallIntToIntoid (0);
  4510.     return SpecialCodeToIntoid (ISC_POSITIVE_INFINITY);
  4511.   }
  4512.  
  4513.   if (IntegerB == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
  4514.   {
  4515.     FreeIntoid (RecycleMe);
  4516.     if (IntegerA == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY))
  4517.       return SmallIntToIntoid (0);
  4518.     return SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY);
  4519.   }
  4520.  
  4521.   if (IntegerA == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
  4522.   {
  4523.     FreeIntoid (RecycleMe);
  4524.     if (IntegerB == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
  4525.       return SmallIntToIntoid (0);
  4526.     return SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY);
  4527.   }
  4528.  
  4529.   if (IntegerB == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
  4530.   {
  4531.     FreeIntoid (RecycleMe);
  4532.     if (IntegerA == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
  4533.       return SmallIntToIntoid (0);
  4534.     return SpecialCodeToIntoid (ISC_POSITIVE_INFINITY);
  4535.   }
  4536.  
  4537.   if (IntoidIsSpecialCode (IntegerA))
  4538.   {
  4539.     FreeIntoid (RecycleMe);
  4540.     return IntegerA;
  4541.   }
  4542.  
  4543.   if (IntoidIsSpecialCode (IntegerB))
  4544.   {
  4545.     FreeIntoid (RecycleMe);
  4546.     return IntegerB;
  4547.   }
  4548.  
  4549.   /* Check for numbers that fit in a long so we can do a simpler long/intrep
  4550.      addition.  Already know that not both are small integers. */
  4551.  
  4552.   if (IntoidIsSmallInt (IntegerA))
  4553.     return NormalizeIntoid (AddLongAndIntRep (IntoidToSmallInt (IntegerA),
  4554.     IntegerB, TRUE /* negate it */, RecycleMe));
  4555.  
  4556.   if (IntoidIsSmallInt (IntegerB))
  4557.     return NormalizeIntoid (AddLongAndIntRep (-IntoidToSmallInt (IntegerB),
  4558.     IntegerA, FALSE, RecycleMe));
  4559.  
  4560.   /* Ok, now adding two Intoids which are IntReps. */
  4561.  
  4562.   return NormalizeIntoid (AddIntRepAndIntRep (IntegerA, FALSE,
  4563.   IntegerB, TRUE /* negate it */, RecycleMe));
  4564. }
  4565.  
  4566.  
  4567.  
  4568. /****** intoids.library/CompareIntoids **************************************
  4569. *
  4570. *   NAME
  4571. *       CompareIntoids -- Signed comparison of two Intoid values.
  4572. *
  4573. *   SYNOPSIS
  4574. *       Result = CompareIntoids( IntegerA, IntegerB )
  4575. *       D0                       D0        D1
  4576. *
  4577. *       LONG CompareIntoids( Intoid, Intoid );
  4578. *
  4579. *   FUNCTION
  4580. *       Compares the size of two Intoids, more efficiently than using a
  4581. *       subtraction.
  4582. *
  4583. *   INPUTS
  4584. *       IntegerA - one input value.
  4585. *       IntegerB - the other input value.
  4586. *
  4587. *   RESULT
  4588. *       Result - returns a long value that depends on the comparison:
  4589. *           -1 for IntegerA < IntegerB,
  4590. *            0 for IntegerA == IntegerB,
  4591. *           +1 for IntegerA > IntegerB.
  4592. *
  4593. *   SEE ALSO
  4594. *       SignOfIntoid(), CompareIntoidMagnitudes().
  4595. *
  4596. *****************************************************************************
  4597. */
  4598.  
  4599. LONG LIBFUNC CompareIntoids (REGD0 Intoid IntegerA, REGD1 Intoid IntegerB)
  4600. {
  4601.   long            ComparisonResult;
  4602.   Intoid          IntegerResult;
  4603.   unsigned short  LengthA;
  4604.   unsigned short  LengthB;
  4605.   IntRepPointer   RepA;
  4606.   IntRepPointer   RepB;
  4607.   BOOL            SignA;
  4608.   BOOL            SignB;
  4609.  
  4610.   /* Special case speed optimization for two IntRep based Intoids. */
  4611.  
  4612.   if (IntoidIsIntRep (IntegerA) && IntoidIsIntRep (IntegerB))
  4613.   {
  4614.     RepA = (IntoidAsPointer) IntegerA;
  4615.     RepB = (IntoidAsPointer) IntegerB;
  4616.  
  4617.     LengthA = RepA->currentLength;
  4618.     LengthB = RepB->currentLength;
  4619.  
  4620.     SignA = RepA->positiveSign;
  4621.     SignB = RepB->positiveSign;
  4622.  
  4623.     ComparisonResult = SignA - SignB; /* Note that signs are 0=neg or 1=pos. */
  4624.     if (ComparisonResult == 0) /* Have to do an effective subtraction. */
  4625.     {
  4626.       /* See which one is bigger, IntegerA or IntegerB. */
  4627.  
  4628.       ComparisonResult = (long) LengthA - (long) LengthB;
  4629.       if (ComparisonResult == 0) /* Same length, compare values. */
  4630.         ComparisonResult = CompareNumberArrays (RepA->numberArray,
  4631.         RepB->numberArray, LengthA);
  4632.  
  4633.       if (ComparisonResult < 0) /* If B is bigger in magnitude. */
  4634.         ComparisonResult = SignB ? -1L : 1L; /* Were doing A-B, so -B. */
  4635.       else if (ComparisonResult > 0) /* If A is bigger in magnitude. */
  4636.         ComparisonResult = SignA ? 1L : -1L;
  4637.       /* Else equal and ComparisonResult is zero. */
  4638.     }
  4639.   }
  4640.   else /* Small integers or special codes or a mixture of things. */
  4641.   {
  4642.     IntegerResult = SubtractIntoids (IntegerA, IntegerB, NULL);
  4643.     ComparisonResult = IntoidToLong (IntegerResult);
  4644.     FreeIntoid (IntegerResult);
  4645.     if (ComparisonResult < 0)
  4646.       ComparisonResult = -1L;
  4647.     else if (ComparisonResult > 0)
  4648.       ComparisonResult = 1L;
  4649.   }
  4650.  
  4651.   return ComparisonResult;
  4652. }
  4653.  
  4654.  
  4655.  
  4656. /****** intoids.library/CompareIntoidMagnitudes *****************************
  4657. *
  4658. *   NAME
  4659. *       CompareIntoidMagnitudes -- Comparison of absolute values.
  4660. *
  4661. *   SYNOPSIS
  4662. *       Result = CompareIntoidMagnitudes( IntegerA, IntegerB )
  4663. *       D0                                D0        D1
  4664. *
  4665. *       LONG CompareIntoidMagnitudes( Intoid, Intoid );
  4666. *
  4667. *   FUNCTION
  4668. *       Compares the absolute values of two Intoids, more efficiently than
  4669. *       using a subtraction of absolute values.
  4670. *
  4671. *   INPUTS
  4672. *       IntegerA - one input value.
  4673. *       IntegerB - the other input value.
  4674. *
  4675. *   RESULT
  4676. *       Result - returns a long value that depends on the comparison:
  4677. *           -1 for abs(IntegerA) < abs(IntegerB),
  4678. *            0 for abs(IntegerA) == abs(IntegerB),
  4679. *           +1 for abs(IntegerA) > abs(IntegerB).
  4680. *
  4681. *   SEE ALSO
  4682. *       SignOfIntoid(), CompareIntoids().
  4683. *
  4684. *****************************************************************************
  4685. */
  4686.  
  4687. LONG LIBFUNC CompareIntoidMagnitudes (REGD0 Intoid IntegerA,
  4688. REGD1 Intoid IntegerB)
  4689. {
  4690.   long            ComparisonResult;
  4691.   Intoid          IntegerResult;
  4692.   unsigned short  LengthA;
  4693.   unsigned short  LengthB;
  4694.   IntRepPointer   RepA;
  4695.   IntRepPointer   RepB;
  4696.   Intoid          TempA;
  4697.   Intoid          TempB;
  4698.  
  4699.   /* Special case speed optimization for two IntRep based Intoids. */
  4700.  
  4701.   if (IntoidIsIntRep (IntegerA) && IntoidIsIntRep (IntegerB))
  4702.   {
  4703.     RepA = (IntoidAsPointer) IntegerA;
  4704.     RepB = (IntoidAsPointer) IntegerB;
  4705.  
  4706.     LengthA = RepA->currentLength;
  4707.     LengthB = RepB->currentLength;
  4708.  
  4709.     /* See which one is bigger, IntegerA or IntegerB. */
  4710.  
  4711.     ComparisonResult = (long) LengthA - (long) LengthB;
  4712.     if (ComparisonResult == 0) /* Same length, compare values. */
  4713.       ComparisonResult = CompareNumberArrays (RepA->numberArray,
  4714.       RepB->numberArray, LengthA);
  4715.   }
  4716.   else /* Small integers or special codes or a mixture of things. */
  4717.   {
  4718.     TempA = AbsoluteIntoid (IntegerA, NULL);
  4719.     TempB = AbsoluteIntoid (IntegerB, NULL);
  4720.     IntegerResult = SubtractIntoids (TempA, TempB, NULL);
  4721.     ComparisonResult = IntoidToLong (IntegerResult);
  4722.     FreeIntoid (TempA);
  4723.     FreeIntoid (TempB);
  4724.     FreeIntoid (IntegerResult);
  4725.   }
  4726.  
  4727.   if (ComparisonResult < 0)
  4728.     ComparisonResult = -1L;
  4729.   else if (ComparisonResult > 0)
  4730.     ComparisonResult = 1L;
  4731.  
  4732.   return ComparisonResult;
  4733. }
  4734.  
  4735.  
  4736.  
  4737. /****** intoids.library/MultiplyIntoids *************************************
  4738. *
  4739. *   NAME
  4740. *       MultiplyIntoids -- Computes value of one Intoid times another.
  4741. *
  4742. *   SYNOPSIS
  4743. *       NewIntoid = MultiplyIntoids( IntegerA, IntegerB, RecycleMe )
  4744. *       D0                           D0        D1        A0
  4745. *
  4746. *       Intoid MultiplyIntoids( Intoid, Intoid, Intoid );
  4747. *
  4748. *   FUNCTION
  4749. *       Does multiplication, IntegerA * IntegerB.
  4750. *
  4751. *   INPUTS
  4752. *       IntegerA - one input value.
  4753. *       IntegerB - the other input value.
  4754. *       RecycleMe - an old Intoid you want to deallocate, or NULL.
  4755. *
  4756. *   RESULT
  4757. *       NewIntoid - newly allocated Intoid containing the value of
  4758. *           (IntegerA * IntegerB), or NULL if out of memory.
  4759. *
  4760. *****************************************************************************
  4761. */
  4762.  
  4763. Intoid LIBFUNC MultiplyIntoids (REGD0 Intoid IntegerA, REGD1 Intoid IntegerB,
  4764. REGA0 Intoid RecycleMe)
  4765. {
  4766.   unsigned short  BitsA;
  4767.   unsigned short  BitsB;
  4768.   long            LongA;
  4769.   long            LongB;
  4770.   Intoid          ResultIntoid;
  4771.  
  4772.   /* If multiplying by zero or not-a-number, return zero. */
  4773.  
  4774.   if (IntegerA == NULL || IntegerA == SmallIntToIntoid (0) ||
  4775.   IntegerB == NULL || IntegerB == SmallIntToIntoid (0))
  4776.   {
  4777.     FreeIntoid (RecycleMe);
  4778.     return SmallIntToIntoid (0);
  4779.   }
  4780.  
  4781.   /* If multiplying by positive 1, return the other argument. */
  4782.  
  4783.   if (IntegerA == SmallIntToIntoid (1))
  4784.     return CopyIntoid (IntegerB, RecycleMe);
  4785.   if (IntegerB == SmallIntToIntoid (1))
  4786.     return CopyIntoid (IntegerA, RecycleMe);
  4787.  
  4788.   /* If multiplying by negative 1, return the negated other argument. */
  4789.  
  4790.   if (IntegerA == SmallIntToIntoid (-1))
  4791.     return NegateIntoid (IntegerB, RecycleMe);
  4792.   if (IntegerB == SmallIntToIntoid (-1))
  4793.     return NegateIntoid (IntegerA, RecycleMe);
  4794.  
  4795.   /* Check for two small integer Intoids.  Just convert to longs and do the
  4796.      multiply.  If it would overflow then make one of them an IntRep and do
  4797.      the multiplication (have to do this after the zero and one tests since
  4798.      MultiplyLongAndIntRep doesn't handle all those cases for the IntRep
  4799.      argument). */
  4800.  
  4801.   if (IntoidIsSmallInt (IntegerA) && IntoidIsSmallInt (IntegerB))
  4802.   {
  4803.     LongA = IntoidToSmallInt (IntegerA);
  4804.     BitsA = 0;
  4805.     if (LongA < 0) LongA = -LongA;
  4806.     while (LongA != 0)
  4807.     {
  4808.       BitsA++;
  4809.       LongA >>= 1;
  4810.     }
  4811.  
  4812.     LongB = IntoidToSmallInt (IntegerB);
  4813.     BitsB = 0;
  4814.     if (LongB < 0) LongB = -LongB;
  4815.     while (LongB != 0)
  4816.     {
  4817.       BitsB++;
  4818.       LongB >>= 1;
  4819.     }
  4820.  
  4821.     if (BitsA + BitsB <= CHAR_PER_LONG * CHAR_BIT - 2)
  4822.       return LongToIntoid (IntoidToSmallInt (IntegerA) *
  4823.       IntoidToSmallInt (IntegerB), RecycleMe);
  4824.  
  4825.     /* Else result may be too big to fit in a long, so convert one argument to
  4826.        an IntRep and do the long vs IntRep multiplication. */
  4827.  
  4828.     RecycleMe = LongToIntRep (IntoidToSmallInt (IntegerB), RecycleMe);
  4829.     if (RecycleMe == NULL)
  4830.       ResultIntoid = NULL;
  4831.     else
  4832.     {
  4833.       ResultIntoid = MultiplyLongAndIntRep (IntoidToSmallInt (IntegerA),
  4834.       RecycleMe, RecycleMe);
  4835.       ResultIntoid = NormalizeIntoid (ResultIntoid);
  4836.     }
  4837.     return ResultIntoid;
  4838.   }
  4839.  
  4840.   /* Check for multiplying by infinity.  The result is infinity. */
  4841.  
  4842.   if (IntegerA == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY) ||
  4843.   IntegerA == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY) ||
  4844.   IntegerB == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY) ||
  4845.   IntegerB == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
  4846.   {
  4847.     LongA = IntoidToLong (IntegerA);
  4848.     LongB = IntoidToLong (IntegerB);
  4849.     FreeIntoid (RecycleMe);
  4850.     if ((LongA < 0) == (LongB < 0))
  4851.       return SpecialCodeToIntoid (ISC_POSITIVE_INFINITY);
  4852.     else /* Have different signs. */
  4853.       return SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY);
  4854.   }
  4855.  
  4856.   if (IntoidIsSpecialCode (IntegerA))
  4857.   {
  4858.     FreeIntoid (RecycleMe);
  4859.     return IntegerA;
  4860.   }
  4861.  
  4862.   if (IntoidIsSpecialCode (IntegerB))
  4863.   {
  4864.     FreeIntoid (RecycleMe);
  4865.     return IntegerB;
  4866.   }
  4867.  
  4868.   /* Check for numbers that fit in a long so we can do a simpler long/intrep
  4869.      multiplication.  Arguments can only be small integers or IntReps at this
  4870.      point, and not both small integers. */
  4871.  
  4872.   if (IntoidIsSmallInt (IntegerA))
  4873.     return NormalizeIntoid (MultiplyLongAndIntRep (IntoidToSmallInt (IntegerA),
  4874.     IntegerB, RecycleMe));
  4875.  
  4876.   if (IntoidIsSmallInt (IntegerB))
  4877.     return NormalizeIntoid (MultiplyLongAndIntRep (IntoidToSmallInt (IntegerB),
  4878.     IntegerA, RecycleMe));
  4879.  
  4880.   /* Have two IntReps, do the multiplication. */
  4881.  
  4882.   return NormalizeIntoid (MultiplyIntRepAndIntRep (IntegerA, IntegerB,
  4883.   RecycleMe));
  4884. }
  4885.  
  4886.  
  4887.  
  4888. /****** intoids.library/DivideIntoids ***************************************
  4889. *
  4890. *   NAME
  4891. *       DivideIntoids -- Computes value of one Intoid divided by another.
  4892. *
  4893. *   SYNOPSIS
  4894. *       NewIntoid = DivideIntoids( IntegerA, IntegerB, RecycleMe )
  4895. *       D0                         D0        D1        A0
  4896. *
  4897. *       Intoid DivideIntoids( Intoid, Intoid, Intoid );
  4898. *
  4899. *   FUNCTION
  4900. *       Does division, IntegerA / IntegerB.
  4901. *
  4902. *   INPUTS
  4903. *       IntegerA - one input value.
  4904. *       IntegerB - the other input value.
  4905. *       RecycleMe - an old Intoid you want to deallocate, or NULL.
  4906. *
  4907. *   RESULT
  4908. *       NewIntoid - newly allocated Intoid containing the value of
  4909. *           (IntegerA / IntegerB), or NULL if out of memory or if
  4910. *           you divided by zero.
  4911. *
  4912. *****************************************************************************
  4913. */
  4914.  
  4915. Intoid LIBFUNC DivideIntoids (REGD0 Intoid IntegerA, REGD1 Intoid IntegerB,
  4916. REGA0 Intoid RecycleMe)
  4917. {
  4918.   long            ComparisonResult;
  4919.   long            LongA;
  4920.   long            LongB;
  4921.  
  4922.   /* Check for divide by zero or not-a-number. */
  4923.  
  4924.   if (IntegerB == NULL || IntegerB == SmallIntToIntoid (0))
  4925.   {
  4926.     DisplayErrorMessage (GetIntoidsMessage (MSG_INTOIDS_DIVIDE_BY_ZERO));
  4927.     FreeIntoid (RecycleMe);
  4928.     return NULL;
  4929.   }
  4930.  
  4931.   /* Most frequent case is two small integer Intoids.  Just
  4932.      convert to longs and do it.  Should never overflow. */
  4933.  
  4934.   if (IntoidIsSmallInt (IntegerA) && IntoidIsSmallInt (IntegerB))
  4935.   {
  4936.     LongA = IntoidToSmallInt (IntegerA);
  4937.     LongB = IntoidToSmallInt (IntegerB);
  4938.     return LongToIntoid (LongA / LongB, RecycleMe);
  4939.   }
  4940.  
  4941.   /* If numerator is zero or NAN or just less than denominator
  4942.      in magnitude, return zero.  This also handles the case
  4943.      where the divisor is infinity and the numerator is less. */
  4944.  
  4945.   ComparisonResult = CompareIntoidMagnitudes (IntegerA, IntegerB);
  4946.  
  4947.   if (IntegerA == NULL || IntegerA == SmallIntToIntoid (0) ||
  4948.   ComparisonResult < 0)
  4949.   {
  4950.     FreeIntoid (RecycleMe);
  4951.     return SmallIntToIntoid (0);
  4952.   }
  4953.  
  4954.   /* If the numerator and denominator are equal then return one or -1. */
  4955.  
  4956.   if (ComparisonResult == 0)
  4957.   {
  4958.     ComparisonResult =
  4959.     (SignOfIntoid (IntegerA) == SignOfIntoid (IntegerB)) ? 1L : -1L;
  4960.     FreeIntoid (RecycleMe);
  4961.     return SmallIntToIntoid (ComparisonResult);
  4962.   }
  4963.  
  4964.   /* If dividing by one, return the other value. */
  4965.  
  4966.   if (IntegerB == SmallIntToIntoid (1))
  4967.     return CopyIntoid (IntegerA, RecycleMe);
  4968.  
  4969.   if (IntegerB == SmallIntToIntoid (-1))
  4970.     return NegateIntoid (IntegerA, RecycleMe);
  4971.  
  4972.   /* Check for numerator of infinity.  The result is infinity. */
  4973.  
  4974.   if (IntegerA == SpecialCodeToIntoid (ISC_POSITIVE_INFINITY) ||
  4975.   IntegerA == SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY))
  4976.   {
  4977.     ComparisonResult =
  4978.     (SignOfIntoid (IntegerA) == SignOfIntoid (IntegerB));
  4979.     FreeIntoid (RecycleMe);
  4980.     if (ComparisonResult)
  4981.       return SpecialCodeToIntoid (ISC_POSITIVE_INFINITY);
  4982.     else /* Have different signs. */
  4983.       return SpecialCodeToIntoid (ISC_NEGATIVE_INFINITY);
  4984.   }
  4985.  
  4986.   /* Handle future special codes.  Already taken care of not-a-number
  4987.      and infinities before here. */
  4988.  
  4989.   if (IntoidIsSpecialCode (IntegerA))
  4990.   {
  4991.     FreeIntoid (RecycleMe);
  4992.     return IntegerA;
  4993.   }
  4994.  
  4995.   if (IntoidIsSpecialCode (IntegerB))
  4996.   {
  4997.     FreeIntoid (RecycleMe);
  4998.     return IntegerB;
  4999.   }
  5000.  
  5001.   /* Check for numbers that fit in a long so we can do a simpler long/intrep
  5002.      division.  Note that IntRep denominator and long numerator won't occur
  5003.      since that result would be zero if the IntRep is normalized. */
  5004.  
  5005.   if (IntoidIsSmallInt (IntegerB))
  5006.     return NormalizeIntoid (DivideIntRepByLong (IntegerA,
  5007.     IntoidToSmallInt (IntegerB), RecycleMe));
  5008.  
  5009.   /* Ok, have two IntReps. */
  5010.  
  5011.   return NormalizeIntoid (DivideIntRepByIntRep (IntegerA, IntegerB,
  5012.   RecycleMe));
  5013. }
  5014.  
  5015.  
  5016.  
  5017. /******************************************************************************
  5018.  * Called by the SAS/C library wrapper when the library is expunged to clean
  5019.  * up globally allocated things.
  5020.  */
  5021.  
  5022. void LIBFUNC __UserLibCleanup (REGA6 struct Library *LibraryBasePntr)
  5023. {
  5024.   if (CurrentCatalog != NULL)
  5025.   {
  5026.     CloseCatalog (CurrentCatalog);
  5027.     CurrentCatalog = NULL;
  5028.   }
  5029.  
  5030.   if (CurrentLocale != NULL)
  5031.   {
  5032.     CloseLocale (CurrentLocale);
  5033.     CurrentLocale = NULL;
  5034.   }
  5035.  
  5036.   if (LocaleBase != NULL)
  5037.   {
  5038.  
  5039.     CloseLibrary (LocaleBase);
  5040.     LocaleBase = NULL;
  5041.   }
  5042.  
  5043.   if (UtilityBase != NULL)
  5044.   {
  5045.     CloseLibrary (UtilityBase);
  5046.     UtilityBase = NULL;
  5047.   }
  5048.  
  5049.   if (IntuitionBase != NULL)
  5050.   {
  5051.     CloseLibrary ((struct Library *) IntuitionBase);
  5052.     IntuitionBase = NULL;
  5053.   }
  5054.  
  5055.   if (SysBase != NULL)
  5056.   {
  5057.     CloseLibrary ((struct Library *) SysBase);
  5058.     SysBase = NULL;  /* Do this last, CloseLibrary uses SysBase! */
  5059.   }
  5060. }
  5061.  
  5062.  
  5063.  
  5064. /******************************************************************************
  5065.  * Library initialisation code called by the SAS/C library wrapper.  Open
  5066.  * other libraries we need, do one time initialisation, returns zero if
  5067.  * successful.
  5068.  */
  5069.  
  5070. long LIBFUNC __UserLibInit (REGA6 struct Library *LibraryBasePntr)
  5071. {
  5072.   while (TRUE)
  5073.   {
  5074.     /* Open our copy of Execbase.  Of course, OpenLibrary needs SysBase
  5075.        defined before it is open, so just use the value from the magic
  5076.        location 4 in memory for this one call.  Needed for memory allocation
  5077.        functions, opening libraries, etc. */
  5078.  
  5079.     SysBase = (struct ExecBase *)*(struct Library **)4;
  5080.     SysBase = (struct ExecBase *) OpenLibrary ((UBYTE *) "exec.library", 0);
  5081.     if (SysBase == NULL)
  5082.       break;
  5083.  
  5084.     /* Open intuition.library (any version, so it works under AmigaDOS 1.3
  5085.        too), just in case we need to display error messages. */
  5086.  
  5087.     IntuitionBase = (struct IntuitionBase *)
  5088.     OpenLibrary ((UBYTE *) "intuition.library", 0);
  5089.     if (IntuitionBase == NULL)
  5090.       break;
  5091.  
  5092.     /* Need the utility library for international string comparison
  5093.        functions and 32 bit multiply and divide subroutines. */
  5094.  
  5095.     UtilityBase = OpenLibrary ((STRPTR) UTILITYNAME, 37);
  5096.     if (UtilityBase == NULL)
  5097.     {
  5098.       DisplayErrorMessage ("Need " UTILITYNAME " version 37.");
  5099.       break;
  5100.     }
  5101.  
  5102.     /* Open the locale library for international string support.  It's
  5103.        optional so a NULL LocaleBase won't stop the program. */
  5104.  
  5105.     LocaleBase = OpenLibrary ((STRPTR) "locale.library", 0);
  5106.  
  5107.     if (LocaleBase != NULL)
  5108.       CurrentLocale = OpenLocale (NULL /* The default country & language */);
  5109.  
  5110.     if (LocaleBase != NULL)
  5111.       CurrentCatalog = OpenCatalog (CurrentLocale /* Can be NULL */,
  5112.       (STRPTR) "Intoids.catalog", OC_BuiltInLanguage, "english", TAG_DONE);
  5113.  
  5114.     return 0;  /* Success! */
  5115.   }
  5116.  
  5117.   return 1;  /* Failure. */
  5118. }
  5119.